I need to create a process that will extract the changes from a table where each row is a snapshot of a row in another table. The real-world problem involves many tables with many fields, but as a simple example, suppose that I have the following snapshot data:
Sequence DateTaken ID Field1 Field2
-------- ----------- ---- ------ ------
1 '2011-01-01' 1 'Red' 2
2 '2011-01-01' 2 'Blue' 10
3 '2011-02-01' 1 'Green' 2
4 '2011-03-01' 1 'Green' 3
5 '2011-03-01' 2 'Purple' 2
6 '2011-04-01' 1 'Yellow' 2
The Sequence
and DateTaken
fields relate directly to the snapshot table itself. The ID
field is the primary key of the source table and Field1
and Field2
are other fields in the same (source) table.
I can get part-way to a solution with a query like this:
WITH Snapshots (Sequence, DateTaken, ID, Field1, Field2, _Index)
AS
(
SELECT Sequence, DateTaken, ID, Field1, Field2, ROW_NUMBER() OVER (ORDER BY ID, Sequence) _Index
FROM #Snapshots
)
SELECT
c.DateTaken, c.ID
, c.Field1 Field1_Current, p.Field1 Field1_Previous, CASE WHEN c.Field1 = p.Field1 THEN 0 ELSE 1 END Field1_Changed
, c.Field2 Field2_Current, p.Field2 Field2_Previous, CASE WHEN c.Field2 = p.Field2 THEN 0 ELSE 1 END Field2_Changed
FROM Snapshots c
JOIN Snapshots p ON p.ID = c.ID AND (p._Index + 1) = c._Index
ORDER BY c.Sequence DESC
The above query will identify what is changing from one snapshot to the next, but it is still not in the form that I need. Each row in the output may contain several changes. At the end of the day, I need one row per change that identifies what field was changed, along with its previous/current values. Fields that have not actually changed will need to be excluded from the final output. So if the above query output is like this:
DateTaken ID Field1_Current Field1_Previous Field1_Changed Field2_Current Field2_Previous Field2_Changed
---------- -- -------------- --------------- -------------- -------------- --------------- --------------
2011-04-01 1 Yellow Green 1 2 3 1
2011-02-01 1 Green Red 1 2 2 0
I need to transform that into something like this:
DateTaken ID Field Previous Current
---------- -- ------- -------- ---------
2011-04-01 1 Field1 Green Yellow
2011-04-01 1 Field2 3 2
2011-02-01 1 Field1 Red Green
I thought I might be able to get there with UNPIVOT, but I've not been able to make that work. I consider any solution involving cursors or similar to be an absolute last resort.
Thanks much for any advice.