比较两个没有唯一键的表

Posted

技术标签:

【中文标题】比较两个没有唯一键的表【英文标题】:Comparing two tables that doesn't have unique key 【发布时间】:2016-11-25 12:53:11 【问题描述】:

我需要比较两个表数据并检查哪些属性不匹配,表具有相同的表定义,但问题是我有一个唯一的键来比较。我尝试使用

CONCAT(CONCAT(CONCAT(table1.A, Table1.B))
=CONCAT(CONCAT(CONCAT(table2.A, Table2.B))

但仍然面临重复的行也尝试了 NVL 在几列上但没有工作

SELECT  
    UT.cat,
    PD.cat
FROM 
    EM UT, EM_63 PD 
WHERE 
    NVL(UT.cat, 1) = NVL(PD.cat, 1) AND
    NVL(UT.AT_NUMBER, 1) = NVL(PD.AT_NUMBER, 1) AND
    NVL(UT.OFFSET, 1) = NVL(PD.OFFSET, 1) AND  
    NVL(UT.PROD, 1) = NVL(PD.PROD, 1)
;

一个表有 34k 条记录,另一个表有 35k 条记录,但是如果我运行上面的查询,行数是 300 万。

表格中的列:

COUNTRY       
CATEGORY   
TYPE    
DESCRIPTION

样本数据:

表 1:

COUNTRY  CATEGORY TYPE   DESCRIPTION       
US          C       T1      In
IN          A       T2      OUT
B           C       T2      IN
Y           C       T1      INOUT

表2:

COUNTRY  CATEGORY TYPE   DESCRIPTION    
US          C       T2      In
IN          B        T2     Out
Q           C       T2      IN

预期输出:

column      Matched  unmatched
COUNTRY         2       1
CATEGORY        2       1
TYPE            2       1
DESCRIPTION     3       0

【问题讨论】:

添加一些示例表数据和预期结果。 (以及格式化文本。) 为什么要三重连接? 请更新您添加数据样本的问题和预期结果 你可以使用这套:(A-B) U (B-A) = (select * from A minus select * from B) union (select * from B minus select * from A) @Varoo - 虽然 Cunning 的建议不会给你最有效的执行,但它们应该会给你正确的结果。您所说的“重复行”是什么意思 - UNION、INTERSECT 和 MINUS 消除了重复,因此您一定是错误地使用了“重复”这个词,或者您没有正确实施建议。 【参考方案1】:

在最一般的情况下(当您可能有重复的行,并且您想查看一个表中存在哪些行但另一个表中不存在时,以及两个表中可能存在哪些行,但该行在第一个表,但在另一个表中 5 次):

这是一个非常常见的问题,有一个已解决的“最佳解决方案”,出于某种原因,大多数人似乎仍然没有意识到这一点,尽管它是多年前在 AskTom 上开发的,并且已经被多次提出。

您不需要连接,不需要任何类型的唯一键,也不需要多次读取任一表。这个想法是添加两列以显示每行来自哪个表,执行 UNION ALL,然后 GROUP BY 除“源”列之外的所有列并显示每个表的计数。像这样的:

select   count(t_1) as count_table_1, count(t_2) as count_table_2, col1, col2, ...
from     (
           select 'x' as t_1, null as t_2, col1, col2, ... 
             from table_1
           union all
           select null as t_1, 'x' as t_2, col1, col2, ...
             from table_2
         )
group by col1, col2, ...
having   count(t_1) != count(t_2)
;

【讨论】:

感谢您的建议,但我们可以得到像 Columnname,matched count,unmatchedcount 这样的输出 @varoo - “匹配计数”是什么意思?您想按列执行此操作吗?我不确定这是否有意义。请发布一个小样本,说明结果应该是什么样子(不要担心如何实现)以及它的含义。 更新了样本数据【参考方案2】:

从这个查询开始,检查这 4 列是否构成一个键。

select      occ_total,occ_ut,occ_pd
           ,count(*)                as records

from       (select      count (*)                               as occ_total
                       ,count (case tab when 'UT' then 1 end)   as occ_ut
                       ,count (case tab when 'PD' then 1 end)   as occ_pd

            from                    select 'UT' as tab,cat,AT_NUMBER,OFFSET,PROD from EM
                        union all   select 'PD'       ,cat,AT_NUMBER,OFFSET,PROD from EM_63 PD
                        ) t

            group by    cat,AT_NUMBER,OFFSET,PROD
            ) t

group by    occ_total,occ_ut,occ_pd     

order by    records desc
;

选择“键”后,您可以使用以下查询查看属性的值

select      count (*)                               as occ_total
           ,count (case tab when 'UT' then 1 end)   as occ_ut
           ,count (case tab when 'PD' then 1 end)   as occ_pd

           ,count (distinct att1)                   as cnt_dst_att1
           ,count (distinct att2)                   as cnt_dst_att2
           ,count (distinct att3)                   as cnt_dst_att3
           ,...
           ,listagg (case tab when 'UT' then att1 end) within group (order by att1) as att1_vals_ut
           ,listagg (case tab when 'PD' then att1 end) within group (order by att1) as att1_vals_pd
           ,listagg (case tab when 'UT' then att2 end) within group (order by att2) as att2_vals_ut
           ,listagg (case tab when 'PD' then att2 end) within group (order by att2) as att2_vals_pd
           ,listagg (case tab when 'UT' then att3 end) within group (order by att3) as att3_vals_ut
           ,listagg (case tab when 'PD' then att3 end) within group (order by att3) as att3_vals_pd  
           ,...

from                    select 'UT' as tab,cat,AT_NUMBER,OFFSET,PROD,att1,att2,att3,... from E M
            union all   select 'PD'       ,cat,AT_NUMBER,OFFSET,PROD,att1,att2,att3,... from EM_63 PD
            ) t

group by    cat,AT_NUMBER,OFFSET,PROD
;

【讨论】:

【参考方案3】:

CONCAT 的问题是,如果您的数据与此类似,您可能会得到无效匹配:

table1.A = '123'
table1.B = '456'

连接到:'123456'

table2.A = '12'
table2.B = '3456'

也连接到:'123456'

您必须单独比较字段:table1.A = table2.A AND table1.B = table2.B

【讨论】:

我试过比较 table1.A =table2.A ,但我也需要不同数据的 count(*)。

以上是关于比较两个没有唯一键的表的主要内容,如果未能解决你的问题,请参考以下文章

django:连接两个没有外键的表

Oracle对没有主键的表分页

Sql Server中的游标最好只能用于有主键或唯一键的表

如何在没有主键的表上按顺序更新表?

在没有唯一键的两个表上选择查询

两个外键的唯一约束始终是不同的组合