SQL比较字段对并将匹配附加到另一个字段

时间:2014-09-03 23:39:30

标签: sql sql-server tsql case

我们有一个大型数据库,并从旧架构中导入旧的归档数据。我们已经根据新旧数据(A和B)创建了两个查询,并且想要标记'具有不同值以供审阅的字段。

我们设置了第三个查询,并手动匹配字段,如下所示:

CREATE VIEW vuAB_COMPARISON AS
SELECT
     A.1
    ,B.1
    ,A.2
    ,B.2
    ,A.3
    ,B.3
    ...
    ...
    ...
    ,CASE 
      WHEN A.PK = B.PK 
        THEN 'RecordMatch' 
      WHEN A.PK <> B.PK 
        THEN 'RecordNoMatch' 
     END AS ComparisonCheck

FROM Table A
INNER JOIN Table B
ON A.PK = B.PK

我们要做的是将所有不匹配的字段附加到ComparisonCheck列。例如,如果A.1&lt;&gt; B.1,那么ComparisonCheck列将是&#39; RecordMatch; Field1_NoMatch&#39;

类似地,如果A.1&lt;&gt; B.1和A.2&lt;&gt; B.2然后,ComparisonCheck列将是&#39; RecordMatch; Field1_NoMatch; Field2_NoMatch&#39;等

我能想到的唯一方法是使用复杂的嵌套case语句。然而,有几十个字段要匹配,所以这将是tedius。

有更好的解决方案吗?我也考虑过将其分成两个查询,但我不确定是否让我更接近解决方案。

注意我已经简化了一些事情,因为实际上连接使用多个字段,而不是来自查询A / B的所有记录都匹配,这就是为什么设置CASE语句的原因。

2 个答案:

答案 0 :(得分:0)

只是一个通用表比较脚本集:

将记录记录在a中,但不记录在b

Select * from tablea a left join tableb b on b.pk = a.pk where b.pk is null

简单的逻辑,当pk在tablea中而不是b时,左连接产生空值,其中b.pk为null,所有都在a中。

将表格反转为b而不是a:

    Select * from tableb b left join tablea a on b.pk = a.pk where a.pk is null

相同的逻辑,只是反转哪个表是第一个和空检查。从技术上讲,您可以使用右连接,而不是在from子句中更改哪个表是第一个

以及表之间的差异:

select a.*,b.* from tablea a inner join tableb b on a.pk = b.pk
where a.col1 <> b.col1 or a.col2 <> col2 or a.col3 <> a.col3 or etc...

这将只列出表之间不同的所有行。不幸的是,你需要在where子句中输入每一列。要将其更改为标记:

select a.pk, case when c.pk is not null then "no match' else 'match found' end
from tablea a 
inner join tableb b on a.pk = b.pk
left join ( select a.pk from tablea a inner join tableb b on a.pk = b.pk
where a.col1 <> b.col1 or a.col2 <> col2 or a.col3 <> a.col3 or etc...) c
on a.pk = c.pk

逻辑正在使用子查询来挑选出在子查询中存在差异的所有PK,并从tablea继续加入它。如果c.pk为null,那么它不在子查询中并且行是相同的,如果c.pk不为null则行中存在差异...一个简单的case语句将其更改为标志。

答案 1 :(得分:0)

UNPIVOT或CROSS APPLY可以让这项工作更轻松。

假设您有两张表:

create table t1 (id int, c1 int, c2 int, c3 int);
create table t2 (id int, c1 int, c2 int, c3 int);

insert into t1 values(0,0,0,0);
insert into t1 values(1,1,1,1);
insert into t1 values(2,2,2,2);
insert into t1 values(3,3,3,3);
--insert into t1 values(4,null,3,3);
--insert into t1 values(5,null,3,3);
insert into t1 values(6,3,3,3); --t2's missing record

insert into t2 values(0,0,0,0); --match
insert into t2 values(1,1,2,1); --c2 mismatch
insert into t2 values(2,2,3,3); --c2,c3 mismatch
insert into t2 values(3,2,2,2); --all mismatch
--insert into t2 values(4,null,3,3);
--insert into t2 values(5,3,null,3);
insert into t2 values(7,2,2,2); --t1's missing record

比较步骤:

  • 取消透视t1和t2,通过生成c_name列将列传输到行。
  • 来自两个垂直表的全外连接
    • 比较ID可以找出丢失的Recoreds
    • 比较值可以找出不匹配的列

with 
vt1 as 
  (select id, c_name , v1
   from t1
   unpivot (v1 for c_name in ([c1],[c2],[c3]) ) as t),
vt2 as 
  (select id, c_name , v2
   from t2
   unpivot (v2 for c_name in ([c1],[c2],[c3]) ) as t)
select distinct coalesce(vt1.id,vt2.id) as id
  ,case when vt1.id is null and vt2.id is not null
        then 'RecordT1Missing' 
        when vt2.id is null and not vt1.id is null
        then 'RecordT2Missing'
        else 'RecordMatch' end as RecordMatchType
  ,case when v1<>v2 then vt1.c_name + '_NoMatch'
        else '' end as ColumnMathType
from vt1
full outer join vt2
on vt1.id=vt2.id and vt1.c_name = vt2.c_name
;

SQLFiddle

这是输出,而不是问题中描述的格式,但有很多方法可以转回其他可读格式,可以留给OP工作:

ID  RECORDMATCHTYPE COLUMNMATHTYPE
 0      RecordMatch 
 1      RecordMatch 
 1      RecordMatch    c2_NoMatch
 2      RecordMatch    
 2      RecordMatch    c2_NoMatch
 2      RecordMatch    c3_NoMatch
 3      RecordMatch    c1_NoMatch
 3      RecordMatch    c2_NoMatch
 3      RecordMatch    c3_NoMatch
 6  RecordT2Missing 
 7  RecordT1Missing 

注意:

  • 我的示例中的所有数据值都定义为整数,但在实际场景中可能有不同的数据类型,应该在unpivot和compare之前转换为varchar。
  • 不幸的是,SqlServer unpivot无法保留空值,所以我用空值注释了所有数据。您还可以添加处理这些空值的条件,但我认为更好的解决方案是将空值传递给一些未使用的值,除非您有进一步处理空值的逻辑。

UPDATE:

使用@ ErikE的帮助,使用CROSS APPLY可以更轻松地处理空值。

with 
vt1 as 
  (select id, c_name , v1
   from t1
   CROSS APPLY (VALUES ('c1',c1),('c2',c2),('c3',c3))
            CrossApplied (c_name, v1) ),
vt2 as 
  (select id, c_name , v2
   from t2
   CROSS APPLY (VALUES ('c1',c1),('c2',c2),('c3',c3))
            CrossApplied (c_name, v2) )
select distinct coalesce(vt1.id,vt2.id) as id
  ,case when vt1.id is null and vt2.id is not null
        then 'RecordT1Missing' 
        when vt2.id is null and not vt1.id is null
        then 'RecordT2Missing'
        else 'RecordMatch' end as RecordMatchType
  ,case when v1<>v2 then vt1.c_name + '_NoMatch'
        when v1 is null and v2 is not null and vt1.id is not null then vt1.c_name + '_T1Missing'
        when v2 is null and v1 is not null and vt2.id is not null then vt1.c_name + '_T2Missing'
        else '' end as ColumnMathType
from vt1
full outer join vt2
on vt1.id=vt2.id and vt1.c_name = vt2.c_name
;

如果这些数据具有空值,将得到以下结果:

ID  RECORDMATCHTYPE COLUMNMATHTYPE
 0      RecordMatch     
 1      RecordMatch     
 1      RecordMatch       c2_NoMatch
 2      RecordMatch       
 2      RecordMatch       c2_NoMatch
 2      RecordMatch       c3_NoMatch
 3      RecordMatch       c1_NoMatch
 3      RecordMatch       c2_NoMatch
 3      RecordMatch       c3_NoMatch
 4      RecordMatch     
 5      RecordMatch     
 5      RecordMatch     c1_T1Missing
 5      RecordMatch     c2_T2Missing
 6  RecordT2Missing     
 7  RecordT1Missing     

它可以找出哪个列和ID为5的表中缺少的数据。