如何测试表中的所有行是不是重复(一列除外)

Posted

技术标签:

【中文标题】如何测试表中的所有行是不是重复(一列除外)【英文标题】:How can I test whether all of the rows in a table are duplicated (except for one column)如何测试表中的所有行是否重复(一列除外) 【发布时间】:2019-06-29 18:12:27 【问题描述】:

我正在使用一个数据仓库表,该表可以拆分为声明的行和计算的行。 我怀疑计算的行是声明行的完美副本(声明/计算列除外)。

我尝试使用 except 子句对此进行测试:

但是所有的记录都返回了。我不相信这是可能的,我怀疑这是由于空值。

有没有办法比较将空值与空值进行比较的记录?

SELECT a, b, c FROM table WHERE clm_cmp_cd = 'clm'
    EXCEPT
SELECT a, b, c FROM table WHERE clm_cmp_cd = 'cmp'

但是所有的记录都返回了。我不相信这是可能的,我怀疑这是由于空值。

有没有办法比较将空值与空值进行比较的记录?

编辑:该解决方案应适用于具有不同类型的任意数量的字段。在这种情况下,我有大约 100 个字段,其中 2/3 可能有空值。这是一个数据仓库,必须预料到一定程度的非规范化。

编辑:我测试了查询,同时将自己限制为非空列,我得到了我预期的结果(什么都没有)。 但是,我仍然想比较可能包含空值的字段。

【问题讨论】:

也可以尝试使用INTERSECT 而不是EXCEPT。也请看***.com/questions/40680708/… DB2 SELECT EXCEPT with WHERE clause的可能重复 Intersect 获取匹配计数,这也存在同样的问题。我确定有重复,但不容易识别(我怀疑这是由于空值) 【参考方案1】:

您的假设似乎是错误的。你可以试试这个:

select a, b, c,
       sum(case when clm_cmp_cd = 'clm' then 1 else 0 end) as num_clm,
       sum(case when clm_cmp_cd = 'cmp' then 1 else 0 end) as num_cmp
from t
group by a, b, c;

这将显示三列的值以及每种类型的匹配数。

您的问题可能是看起来相似的值并不完全相同。这可能是由于浮点数的细微差异或字符串中不匹配的字符(例如前导空格)造成的。

【讨论】:

我正在处理任意数量的字段(在本例中为 106)。它们可以是任何类型。这个解决方案会显示有一个匹配的对,但它不会告诉我字段值是否发生了变化。 另外,我的假设是这些行是完全重复的(包括浮点数、空格等......) @JoshuaFarina 这是什么意思 - but it doesn't tell me whether the field values have changed?您能否提供一些示例数据(当然不是针对所有 106 列 :))以及预期的结果? 谢谢。我想我需要考虑一下你的代码在做什么。出于某种原因,这对我来说并不直观。实际上,按所有约 100 个字段进行分组非常有帮助,并有助于隔离差异所在(以毫秒为单位的时间戳)。【参考方案2】:

让我们看看 DB2 如何处理 GROUP BYINTERSECT 中的 NULL 值:

with t(a, b, clm_cmp_cd) as (values
  (   1, 1, 'clm')
, (   1, 1, 'cmp')
, (null, 1, 'clm')
, (null, 1, 'cmp')
, (   2, 1, 'cmp')
)
select a, b
from t
where clm_cmp_cd='clm'
  intersect
select a, b
from t
where clm_cmp_cd='cmp';

with t(a, b, clm_cmp_cd) as (values
  (   1, 1, 'clm')
, (   1, 1, 'cmp')
, (null, 1, 'clm')
, (null, 1, 'cmp')
, (   2, 1, 'cmp')
)
select a, b
from t
where clm_cmp_cd in ('clm', 'cmp')
group by a, b
having count(1)>1;

两个查询返回相同的结果:

     A  B
    -- --
     1  1
<null>  1

NULL 值被这些运算符视为相同。 如果您的表中有太多列而无法在查询中手动指定它们,您可以使用以下查询生成列列表:

select listagg(colname, ', ')
from syscat.columns
where tabschema='MYSCHEMA' and tabname='TABLE' and colname<>'CLM_CMP_CD';

【讨论】:

以上是关于如何测试表中的所有行是不是重复(一列除外)的主要内容,如果未能解决你的问题,请参考以下文章

SQL如何查询出某一列中不同值出现的次数?

从Oracle中删除表中的重复行

更新表中所有行中的一列

如何获取表中的所有数据,如果在一列中重复相同的值,该行应该计数一次?

SQL查询从通配符列等于值的所有表中选择所有行[重复]

SQL查询从通配符列等于值的所有表中选择所有行[重复]