查找所有已更改的行并将 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
解释:
以下是 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
) 相同 EmployeeNo
和 Col
的值。
需要写入 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
解释:
以下是 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
) 相同 EmployeeNo
和 Col
的值。