I have a database that consists of order details. We have to track and record any changes made to any of the tables. Therefore, we have a single delta table that will record what was changed (which table, which field, the old value, and the new value).I have some code that creates a very simple DB for proof of concept. However, I was wondering if there is a cleaner/nicer way of recording the deltas using PIVOT rather than lots of CASE statements for EVERY field??CREATE DATABASE TESTGOUSE [TEST]GO/*Msg 8672, Level 16, State 1, Line 34The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.This means that we will have to perform a merge inserting into staging as well as a merge inserting from staging into repository*/CREATE TABLE Test1 (ID INT, SomeText1 CHAR(1), SomeText2 CHAR(1))CREATE TABLE Test2 (ID INT, SomeText1 CHAR(1), SomeText2 CHAR(1), SomeText3 CHAR(1))CREATE TABLE StagingTest1 (ID INT, SomeText1 CHAR(1), SomeText2 CHAR(1))CREATE TABLE StagingTest2 (ID INT, SomeText1 CHAR(1), SomeText2 CHAR(1), SomeText3 CHAR(1))CREATE TABLE TestDelta (ID INT, TableName VARCHAR(50), FieldChanged VARCHAR(20), OldValue VARCHAR(20), NewValue VARCHAR(20), UpdatedDateTime DATETIME)INSERT INTO StagingTest1 (ID,SomeText1, SomeText2)SELECT 4, 'f','a'UNION ALL SELECT 2, 'b','b'GOINSERT INTO StagingTest2 (ID,SomeText1, SomeText2, SomeText3)SELECT 24, 'e','a','1'UNION ALL SELECT 20, 'a','w','2'UNION ALL SELECT 25, 'a','x','2'GOINSERT INTO Test1 (ID,SomeText1, SomeText2)SELECT 1, 'a','a'UNION ALL SELECT 2, 'b','a'UNION ALLSELECT 3, 'c','a'UNION ALL SELECT 4, 'd','a'GOINSERT INTO Test2 (ID,SomeText1, SomeText2, SomeText3)SELECT 20, 'a','z','1'UNION ALL SELECT 21, 'b','z','1'UNION ALLSELECT 22, 'c','z','1'UNION ALL SELECT 23, 'd','z','1'GO--SELECT * FROM StagingTest1--SELECT * FROM Test1GOCREATE TABLE #Test1 (ID1 int, OldValue1 CHAR(1), OldValue2 CHAR(1), [Action] nvarchar(10), ID2 int, NewValue1 CHAR(1), NewValue2 CHAR(1), ActionDateTime datetime ); CREATE TABLE #Test2 (ID1 int, OldValue1 CHAR(1), OldValue2 CHAR(1), OldValue3 CHAR(1), [Action] nvarchar(10), ID2 int, NewValue1 CHAR(1), NewValue2 CHAR(1), NewValue3 CHAR(1), ActionDateTime datetime );MERGE Test1 AS TargetUSING (SELECT ID, SomeText1, SomeText2 FROM StagingTest1) AS Source (ID, SomeText1, SomeText2)ON (Target.ID = Source.ID)WHEN MATCHED THENUPDATE SET SomeText1 = Source.SomeText1, SomeText2 = Source.SomeText2WHEN NOT MATCHED THEN INSERT (ID, SomeText1, SomeText2)VALUES(Source.ID, Source.SomeText1, Source.SomeText2)OUTPUT deleted.*, $action, inserted.*, CURRENT_TIMESTAMP INTO #Test1;MERGE Test2 AS TargetUSING (SELECT ID, SomeText1, SomeText2, SomeText3 FROM StagingTest2) AS Source (ID, SomeText1, SomeText2, SomeText3)ON (Target.ID = Source.ID)WHEN MATCHED THENUPDATE SET SomeText1 = Source.SomeText1, SomeText2 = Source.SomeText2, SomeText3 = Source.SomeText3WHEN NOT MATCHED THEN INSERT (ID, SomeText1, SomeText2, SomeText3)VALUES(Source.ID, Source.SomeText1, Source.SomeText2, Source.SomeText3)OUTPUT deleted.*, $action, inserted.*, CURRENT_TIMESTAMP INTO #Test2;--SELECT * FROM #Test1--SELECT * FROM #Test2-- Insert into TestDelta from Test1INSERT INTO TestDeltaSELECT ID1 AS ID, 'Test1', CASE WHEN OldValue1 <> NewValue1 THEN 'SomeText1' END AS FieldName, CASE WHEN OldValue1 <> NewValue1 THEN OldValue1 END AS OldValue, CASE WHEN OldValue1 <> NewValue1 THEN NewValue1 END AS NewValue, CURRENT_TIMESTAMPFROM #Test1 WHERE [Action] = 'UPDATE'AND OldValue1 <> NewValue1UNION ALLSELECT ID1 AS ID, 'Test1', CASE WHEN OldValue2 <> NewValue2 THEN 'SomeText2' END AS FieldName, CASE WHEN OldValue2 <> NewValue2 THEN OldValue2 END AS OldValue, CASE WHEN OldValue2 <> NewValue2 THEN NewValue2 END AS NewValue, CURRENT_TIMESTAMPFROM #Test1 WHERE [Action] = 'UPDATE'AND OldValue2 <> NewValue2-- Insert into TestDelta from Test2INSERT INTO TestDeltaSELECT ID1 AS ID, 'Test2', CASE WHEN OldValue1 <> NewValue1 THEN 'SomeText1' END AS FieldName, CASE WHEN OldValue1 <> NewValue1 THEN OldValue1 END AS OldValue, CASE WHEN OldValue1 <> NewValue1 THEN NewValue1 END AS NewValue, CURRENT_TIMESTAMPFROM #Test2 WHERE [Action] = 'UPDATE'AND OldValue1 <> NewValue1UNION ALLSELECT ID1 AS ID, 'Test2', CASE WHEN OldValue2 <> NewValue2 THEN 'SomeText2' END AS FieldName, CASE WHEN OldValue2 <> NewValue2 THEN OldValue2 END AS OldValue, CASE WHEN OldValue2 <> NewValue2 THEN NewValue2 END AS NewValue, CURRENT_TIMESTAMPFROM #Test2 WHERE [Action] = 'UPDATE'AND OldValue2 <> NewValue2UNION ALLSELECT ID1 AS ID, 'Test2', CASE WHEN OldValue3 <> NewValue3 THEN 'SomeText3' END AS FieldName, CASE WHEN OldValue3 <> NewValue3 THEN OldValue3 END AS OldValue, CASE WHEN OldValue3 <> NewValue3 THEN NewValue3 END AS NewValue, CURRENT_TIMESTAMPFROM #Test2 WHERE [Action] = 'UPDATE'AND OldValue3 <> NewValue3DROP TABLE #Test1DROP TABLE #Test2SELECT * FROM TestDeltaGOUSE [master]GODROP DATABASE [TEST]
Hearty head pats