如何使用SQL干净地输出表diff

如何使用SQL干净地输出表diff,sql,sql-server,compare,Sql,Sql Server,Compare,我正在研究一种解决方案来帮助比较两个表之间的数据。假设我有这两张桌子 Table: Clients_old ---------------------------------------------- ClientID FirstName LastName Age ---------------------------------------------- 1 John Doe 20 2 Jan

我正在研究一种解决方案来帮助比较两个表之间的数据。假设我有这两张桌子

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和一些丑陋的case逻辑来输出上面的差异

---------------------------------------------------------------------------------------------------------
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中是否有方法将差异格式化为这样的格式

-----------------------------------------------------
ClientID    ColumnName      OldValue    UpdatedValue
-----------------------------------------------------
1           Age             20          99  
2           LastName        Doe         Smith
2           Age             20          99

我知道如何使用C实现,但我很好奇是否有SQL解决方案。

您可以在SQL Server中取消PIVOT。为此,我可以建议:

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,则逻辑会稍微复杂一些


注意,这种方法假定列类型都是字符串。有很多方法可以解决这个问题,但代码要复杂一些。

您可以在SQL Server中取消PIVOT。为此,我可以建议:

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,则逻辑会稍微复杂一些

注意,这种方法假定列类型都是字符串。有很多方法可以解决这个问题,但代码要复杂一些。

戈登的解决方案会更有效

但是,这里有一种方法不区分数据类型,并且更具动态性,不必指定字段

示例或

戈登的解决方案会更有效

但是,这里有一种方法不区分数据类型,并且更具动态性,不必指定字段

示例或


太棒了,我认为这给了我一个很好的工作起点。谢谢!太棒了,我认为这给了我一个很好的工作起点。谢谢!很高兴知道。非常感谢。我也会试试这个,看看有多少性能是我比较的一个因素。@ShawnM请告诉我。我总是对真实的文字基准感兴趣。@johncapelletti。正如你的许多回答一样,这是一个相当了不起的政变。但是,它仍然是数据类型敏感的,因为结果列是varchar,并且在结果集中必须是同一时间。@GordonLinoff最终结果是varchar,但日期和数字端口很好地覆盖。但是,如果表A和B中的列X具有不同的数据类型,则比较将确实失败。我在发现/迁移阶段使用过类似的技术。@GordonLinoff请参阅更新的dbFiddle for int和dates,例如Good to know。非常感谢。我也会试试这个,看看有多少性能是我比较的一个因素。@ShawnM请告诉我。我总是对真实的文字基准感兴趣。@johncapelletti。正如你的许多回答一样,这是一个相当了不起的政变。但是,它仍然是数据类型敏感的,因为结果列是varchar,并且在结果集中必须是同一时间。@GordonLinoff最终结果是varchar,但日期和数字端口很好地覆盖。但是,如果表A和B中的列X具有不同的数据类型,则比较将确实失败。我在发现/迁移阶段使用过类似的技术。@GordonLinoff请参见更新的DbFIDLE中的int和dates
ClientID    Field    OldValue   NewValue
1           Age      20         99
2           Age      20         99
2           LastName Doe        Smith