查找所有已更改的行并将 old-Newvalue 写入 SQL Server 2012 中的不同 table

Find all rows that have changed and write old-Newvalue to different table in SQL Server 2012

需要写入 table 在两次数据切割之间值发生变化的所有行。 这必须在 sql 中完成,并且不能使用任何第三方工具。

我可以使用 "Except" 轻松找到 2 个数据切割之间的差异。 我没有尝试过 chksum 但添加了一列以防万一。

我正在苦苦挣扎并需要你帮助的是 如何将我的发现中的所有数据提取到我的#Changes table?

想要的结果

EmployeeId ColumnName OldValue NewValue 3 MaritalStatus 单身已婚 3 姓马龙埃文斯 10 MaritalStatus 单身已婚

设置测试数据 如果您注意到,虚拟数据设置(2 个 ID 为 (3,10) 的员工有变化) 员工 ID(3) 有 2 列更改。

IF OBJECT_ID('tempdb..#Employee') IS NOT NULL DROP TABLE #Employee
GO
IF OBJECT_ID('tempdb..#Changes') IS NOT NULL DROP TABLE #Changes
GO

CREATE TABLE #Employee
(
    [Id] [int] NOT NULL,  
    EmployeeNo INT NOT NULL, 
    [DataCut] [int] NULL,
    [Name] [varchar](50) NULL,
    [Surname] [varchar](50) NULL,
    [Gender] [varchar](10) NULL,
    [MaritalStatus] [varchar](10) NULL,
    [Chksum] [int] NULL,

    CONSTRAINT [PK_#Employee] 
        PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]

CREATE TABLE #Changes
(
    [EmployeeNo] [int] ,
    [ColumnName] [varchar](50) NULL,
    [OldValue] [varchar](50) NULL,
    [NewValue] [varchar](50) NULL
)

INSERT INTO #Employee([Id], EmployeeNo,[DataCut], [Name], [Surname], [Gender], [MaritalStatus],[Chksum])
SELECT 1, 1,1, N'Jo', N'Bloggs', N'Male', N'Single', NULL UNION ALL
SELECT 2, 2,1, N'Mark', N'Smith', N'Male', N'Single', NULL UNION ALL
SELECT 3, 3,1, N'Jenny', N'Malone', N'Female', N'Single', NULL UNION ALL
SELECT 4, 4,1, N'Mario', N'Rossi', N'Male', N'Single', NULL UNION ALL
SELECT 5, 5,1, N'Richard', N'Jones', N'Male', N'Single', NULL UNION ALL
SELECT 6, 1,2, N'Jo', N'Bloggs', N'Male', N'Single', NULL UNION ALL
SELECT 7, 2,2, N'Mark', N'Smith', N'Male', N'Single', NULL UNION ALL
SELECT 8, 3,2, N'Jenny', N'Evans', N'Female', N'Married', NULL UNION ALL
SELECT 9, 4,2, N'Mario', N'Rossi', N'Male', N'Single', NULL UNION ALL
SELECT 10,5,2, N'Richard', N'Jones', N'Male', N'Married', NULL

--Find all the Rows that have changed between 2 datacuts using EXCEPT
SELECT EmployeeNo,Name, Surname, Gender, MaritalStatus 
FROM #Employee 
WHERE DataCut=1

EXCEPT
SELECT EmployeeNo,Name, Surname, Gender, MaritalStatus 
FROM #Employee 
WHERE DataCut=2

UNION

--do the opposite so that we get all the rows.
SELECT EmployeeNo,Name, Surname, Gender, MaritalStatus 
FROM #Employee 
WHERE DataCut=2

EXCEPT
SELECT EmployeeNo,Name, Surname, Gender, MaritalStatus 
FROM #Employee 
WHERE DataCut=1    


--HOW DO I FILL MY #CHANGES TABLES TO MATCH MY WANTED RESULT?

 DROP TABLE #Changes
 DROP TABLE #Employee

您可以使用 UNPIVOT:

;WITH UnpivotedTable AS (
SELECT Id, EmployeeNo, DataCut, Val, Col           
FROM
   (SELECT Id, EmployeeNo, DataCut, CAST(Name AS VARCHAR(50)) AS Name, 
           CAST(Surname AS VARCHAR(50)) AS Surname,
           CAST(Gender AS VARCHAR(50)) AS Gender, 
           CAST(MaritalStatus AS VARCHAR(50)) AS MaritalStatus
    FROM #Employee) AS src
UNPIVOT 
   (Val FOR Col IN 
      (Name, Surname, Gender, MaritalStatus)) AS unpvt
)
SELECT t1.Id As EmployeeId,
       t1.Col AS ColumnName,
       t1.Val AS OldValue, 
       t2.Val AS NewValue
FROM UnpivotedTable AS t1
INNER JOIN UnpivotedTable AS t2 
   ON t1.EmployeeNo = t2.EmployeeNo AND t1.Col = t2.Col AND 
      t1.DataCut = 1 AND t2.DataCut = 2
WHERE t1.Val <> t2.Val

Demo here

解释:

以下是 CTE(对于 EmployeeNo = 1)返回的数据的摘录:

Id  EmployeeNo  DataCut Val      Col
---------------------------------------------
1   1           1       Jo       Name
1   1           1       Bloggs   Surname
1   1           1       Male     Gender
1   1           1       Single   MaritalStatus
6   1           2       Jo       Name
6   1           2       Bloggs   Surname
6   1           2       Male     Gender
6   1           2       Single   MaritalStatus

使用上面的 table 表达式,我们可以很容易地得到执行 INNER JOIN 操作的预期结果:我们只需要比较 'old' (DataCut = 1) 与 new ( DataCut = 2) 相同 EmployeeNoCol 的值。