Nếu tôi chưa bỏ lỡ bất cứ điều gì:
WITH ranked AS (
SELECT
ChangeDate,
ColPK,
Col1,
Col2,
Col3,
Col4,
Col5,
OverallRank = ROW_NUMBER() OVER (PARTITION BY ColPK ORDER BY ChangeDate),
Col1Rank = ROW_NUMBER() OVER (PARTITION BY ColPK, Col1 ORDER BY ChangeDate),
Col2Rank = ROW_NUMBER() OVER (PARTITION BY ColPK, Col2 ORDER BY ChangeDate),
Col3Rank = ROW_NUMBER() OVER (PARTITION BY ColPK, Col3 ORDER BY ChangeDate),
Col4Rank = ROW_NUMBER() OVER (PARTITION BY ColPK, Col4 ORDER BY ChangeDate),
Col5Rank = ROW_NUMBER() OVER (PARTITION BY ColPK, Col5 ORDER BY ChangeDate)
FROM AuditTable
)
, ranked2 AS (
SELECT
ChangeDate,
ColPK,
Col1,
Col2,
Col3,
Col4,
Col5,
Col1Group = RANK() OVER (PARTITION BY ColPK, Col1 ORDER BY OverallRank - Col1Rank),
Col2Group = RANK() OVER (PARTITION BY ColPK, Col2 ORDER BY OverallRank - Col2Rank),
Col3Group = RANK() OVER (PARTITION BY ColPK, Col3 ORDER BY OverallRank - Col3Rank),
Col4Group = RANK() OVER (PARTITION BY ColPK, Col4 ORDER BY OverallRank - Col4Rank),
Col5Group = RANK() OVER (PARTITION BY ColPK, Col5 ORDER BY OverallRank - Col5Rank),
Col1Rank = ROW_NUMBER() OVER (PARTITION BY ColPK, Col1, OverallRank - Col1Rank ORDER BY ChangeDate),
Col2Rank = ROW_NUMBER() OVER (PARTITION BY ColPK, Col2, OverallRank - Col2Rank ORDER BY ChangeDate),
Col3Rank = ROW_NUMBER() OVER (PARTITION BY ColPK, Col3, OverallRank - Col3Rank ORDER BY ChangeDate),
Col4Rank = ROW_NUMBER() OVER (PARTITION BY ColPK, Col4, OverallRank - Col4Rank ORDER BY ChangeDate),
Col5Rank = ROW_NUMBER() OVER (PARTITION BY ColPK, Col5, OverallRank - Col5Rank ORDER BY ChangeDate)
FROM ranked
),
unpivoted AS (
SELECT
r.ChangeTime,
r.ColPK,
x.ColName,
ColRank = CASE x.Colname
WHEN 'Col1' THEN Col1Group
WHEN 'Col2' THEN Col2Group
WHEN 'Col3' THEN Col3Group
WHEN 'Col4' THEN Col4Group
WHEN 'Col5' THEN Col5Group
END,
Value = CASE x.Colname
WHEN 'Col1' THEN CONVERT(nvarchar(100), r.Col1)
WHEN 'Col2' THEN CONVERT(nvarchar(100), r.Col2)
WHEN 'Col3' THEN CONVERT(nvarchar(100), r.Col3)
WHEN 'Col4' THEN CONVERT(nvarchar(100), r.Col4)
WHEN 'Col5' THEN CONVERT(nvarchar(100), r.Col5)
END
FROM ranked2 r
INNER JOIN (VALUES ('Col1'), ('Col2'), ('Col3'), ('Col4'), ('Col5')) x (ColName)
ON x.ColName = 'Col1' AND Col1Rank = 1
OR x.ColName = 'Col2' AND Col2Rank = 1
OR x.ColName = 'Col3' AND Col3Rank = 1
OR x.ColName = 'Col4' AND Col4Rank = 1
OR x.ColName = 'Col5' AND Col5Rank = 1
)
SELECT
new.ChangeTime,
new.ColPK,
new.ColName,
old.Value AS OldValue,
new.Value AS NewValue
FROM unpivoted new
LEFT JOIN unpivoted old
ON new.ColPK = old.ColPK
AND new.ColName = old.ColName
AND new.ColRank = old.ColRank + 1
Về cơ bản, ý tưởng là xếp hạng các nhóm liền kề có giá trị giống hệt nhau và chọn lần xuất hiện đầu tiên của mọi giá trị. Điều đó được thực hiện cho mọi cột có giá trị đang được kiểm tra và các cột không được chia trong quá trình này. Sau đó, tập hợp hàng không được phân chia sẽ được kết hợp với chính nó, tức là đối với mọi tên PK và cột, mọi hàng đều được so khớp với tập hợp trước của nó (dựa trên xếp hạng) để nhận được giá trị cũ trong cùng một hàng cho tập kết quả cuối cùng.