如何使用SQL干净地输出表diff
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用SQL干净地输出表diff相关的知识,希望对你有一定的参考价值。
我正在研究一种解决方案,以帮助比较两个表之间的数据。说我有这两张桌子
Table: Clients_old
----------------------------------------------
ClientID FirstName LastName Age
----------------------------------------------
1 John Doe 20
2 Jane Doe 20
Table: Clients_updated
----------------------------------------------
ClientID FirstName LastName Age
----------------------------------------------
1 John Doe 99
2 Jane Smith 99
现在,我正在使用EXCEPT和一些丑陋的案例逻辑来输出上面的差异。
---------------------------------------------------------------------------------------------------------
ClientID FirstName_Old FirstName_Updated LastName_Old LastName_Updated Age_Old Age_Updated
---------------------------------------------------------------------------------------------------------
1 NULL NULL NULL NULL 20 99
2 NULL NULL Doe Smith 20 99
这是一个开始,但我想清理输出。鉴于这两个表,SQL中是否有一种方法可以获得这样的diff格式?
-----------------------------------------------------
ClientID ColumnName OldValue UpdatedValue
-----------------------------------------------------
1 Age 20 99
2 LastName Doe Smith
2 Age 20 99
我知道如何使用C#来实现它,但我很好奇是否有SQL解决方案。
答案
您可以在SQL Server中取消隐藏。为此,我建议:
with co as (
select v.*
from clients_old co cross apply
(values (co.client_id, co.firstname, 'firstname'),
(co.client_id, co.lastname, 'lastname'),
(co.client_id, co.age, 'age')
) v(client_id, val, col)
),
cu as (
select v.*
from clients_updated cu cross apply
(values (cu.client_id, cu.firstname, 'firstname'),
(cu.client_id, cu.lastname, 'lastname'),
(cu.client_id, cu.age, 'age')
) v(client_id, val, col)
)
select co.client_id, co.col, co.val as old_value, cu.val as updated_value
from co join
cu
on co.client_id = cu.client_id and co.col = cu.col and
co.val <> cu.val;
如果val
可以是NULL
,那么逻辑会稍微复杂一些。
请注意,此方法确实假定列类型都是字符串。有很多方法可以解决这个问题,但代码有点复杂。
另一答案
戈登的解决方案将更具性能。
但是,这里有一种方法不是数据类型敏感的,而且更加动态,不必指定字段。
例子或dbFiddle
Select A.ClientID
,C.Field
,OldValue = max(case when Src='Old' then Value end)
,NewValue = max(case when Src='New' then Value end)
From (
Select Src='Old',* from Clients_old
Union All
Select Src='New',* from Clients_new
) A
Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
Cross Apply (
Select Field = a.value('local-name(.)','varchar(100)')
,Value = a.value('.','varchar(max)')
From B.XMLData.nodes('/row') as C1(n)
Cross Apply C1.n.nodes('./@*') as C2(a)
Where a.value('local-name(.)','varchar(100)') not in ('Src','ClientID')
) C
Group By A.ClientID,C.Field
Having max(case when Src='Old' then Value end) <> max(case when Src='New' then Value end)
or count(*)=1
返回
ClientID Field OldValue NewValue
1 Age 20 99
2 Age 20 99
2 LastName Doe Smith
以上是关于如何使用SQL干净地输出表diff的主要内容,如果未能解决你的问题,请参考以下文章
如何干净地使用 QuickSort 对链表进行排序 - Python