计算重复项时自我加入vs组

时间:2014-03-13 14:02:48

标签: sql oracle group-by duplicates self-join

我正在尝试根据Oracle数据库中的表的列来计算重复项。此查询使用group by:

select count(dockey), sum(total)
from
(
select doc1.xdockeyphx dockey, count(doc1.xdockeyphx) total
from ecm_ocs.docmeta doc1
where doc1.xdockeyphx is not null
group by doc1.xdockeyphx
having count(doc1.xdockeyphx) > 1
)

返回count = 94408sum(total) = 219330。我认为这是正确的价值。

现在,使用自联接尝试此其他查询:

select count(distinct(doc1.xdockeyph))
from ecm_ocs.docmeta doc1, ecm_ocs.docmeta doc2
where doc1.did > doc2.did
and doc1.xdockeyphx = doc2.xdockeyphx
and doc1.xdockeyphx is not null
and doc2.xdockeyphx is not null

结果也是94408,但是这一个:

select count(*)
from ecm_ocs.docmeta doc1, ecm_ocs.docmeta doc2
where doc1.did > doc2.did
and doc1.xdockeyphx = doc2.xdockeyphx
and doc1.xdockeyphx is not null
and doc2.xdockeyphx is not null

返回1567466,我认为这是错误的。

我用来查找重复项的列是XDOCKEYPHX,DID是表的主键。

为什么值sum(total)与上次查询的结果不同?我不明白为什么最后一个查询返回的行数比预期多。

4 个答案:

答案 0 :(得分:1)

您不需要上一个where子句的复杂性

where doc1.did > doc2.did
and doc1.xdockeyphx = doc2.xdockeyphx
and doc1.xdockeyphx is not null
and doc2.xdockeyphx is not null

如果您考虑一下,doc2.xdockeyphx如果doc1.xdockeyphx不为空,则select count(*) from ecm_ocs.docmeta doc1 join ecm_ocs.docmeta doc2 on doc1.xdockeyphx = doc2.xdockeyphx where doc1.xdockeyphx is not null and doc1.did > doc2.did 不能为空。也许通过加入表格可以更好地表达....

{{1}}

您的前两个查询会报告不同/分组的结果,其中您的最后一个只报告所有结果,这就是计数差异的原因。

答案 1 :(得分:0)

在第三个查询中,由于使用了(*),列名称会重复,您应该将select count(*)替换为select count(doc1.*)

答案 2 :(得分:0)

让我们保持简单。

SELECT FROM_ID,
       TO_ID
FROM   TABLE1;

提取

5    1
5    2
5    3
5    4
5    5

注意: To Id是此表中的PK

在您的第一个查询中(当然我更改了谓词)

SELECT COUNT ( DOCKEY ), SUM ( TOTAL )
FROM   (SELECT   DOC1.TO_ID DOCKEY, COUNT ( DOC1.TO_ID ) TOTAL
        FROM     TABLE1 DOC1
        GROUP BY DOC1.TO_ID
        HAVING   COUNT ( DOC1.TO_ID ) > 0);

制作

5    5

在这里,我选择了按TO_ID分组的行,这些行将在子查询中生成五行,然后主查询中的聚合会将其计为5。

现在在第二个查询中,即使用第三个替换选择COUNT(*),你应该得到相同的计数。原因是我正在加入PK。

SELECT COUNT ( DISTINCT ( DOC1.TO_ID ) )
FROM   TABLE1 DOC1, TABLE1 DOC2
WHERE  DOC1.TO_ID = DOC2.TO_ID;

5


SELECT COUNT(*)
FROM   TABLE1 DOC1, TABLE1 DOC2
WHERE  DOC1.TO_ID = DOC2.TO_ID;

5

但是在你的情况下,你没有在连接中使用PK,而是将它用作谓词。

自联接中的

TABLE1.COL1 = TABLE1.COL1将使其成为一个JOIN ON 自我加入中的TABLE1.COL1 > TABLE1.COL1会将其设为笛卡尔积。

所以在你的第二个查询中,你使用了DISTINCT,它保存了你的重复项而不是第三个,这只是返回行的计数。要检查这一点,您可以执行select *

答案 3 :(得分:0)

感谢@vogomatix,因为他的回答帮助我理解了我的问题以及我错在哪里。最后一个查询实际上导致多行显示每对重复项而没有重复,但它不适合将它们计算为来自第一个的sum(total)。鉴于这种情况:

DID | XDOCKEYPHX
---------------
1   |    1
2   |    1
3   |    1
4   |    2
5   |    2
6   |    3
7   |    3
8   |    3
9   |    3

第一个内部查询将返回

DID | XDOCKEYPHX
---------------
1   |    3
2   |    2
3   |    4

完整查询将为count = 3,这意味着有3个文档包含n个重复项,以及总重复文档sum(total) = 9

现在,第二个和第三个查询,如果我们只使用select *,将提供类似的内容:

DID_1 | XDOCKEYPHX | DID_2
--------------------------
2     |     1      |    1
3     |     1      |    1
3     |     1      |    2
5     |     2      |    4
7     |     3      |    6
8     |     3      |    6
8     |     3      |    7
9     |     3      |    6
9     |     3      |    7
9     |     3      |    8

现在,第二个查询select count(distinct(xdockeyphx))将给出正确的值3,但第三个查询select count(*)将给出10,这对我来说是不正确的,因为我想知道重复的总和对于每个DID(9)。第三个查询给你的是所有重复对,所以你可以比较它们或其他什么。我的误解是认为如果我计算了第三个查询中的所有行,我应该得到每个DID(第一个查询的sum(total))的重复数之和,这是一个错误的想法,现在我意识到了。 / p>