Postgresql 不正确的 COUNT() 值与左外连接
Postgresql incorrect COUNT() value with left outer join
我在 postgresql 9.3 中使用 LEFT OUTER JOIN 时遇到计数聚合问题。
当我执行没有左外连接的标准语句时,它 returns 正确计数,在本例中为 3。当语句变得更复杂时,如下面的语句,它 returns 7 相反,这是不正确的。
只有部分 count() 聚合不正确,大多数是正确的。是什么原因造成的?我应该使用不同的联接吗?
SELECT country_code,
period,
COUNT(commissions.id) AS count,
SUM(commissions.total) AS total,
SUM(CASE WHEN commission_adjustments.is_bonus is True THEN commission_adjustments.total else 0 END) AS bonus
FROM commissions
LEFT OUTER JOIN commission_adjustments ON commissions.id = commission_adjustments.commission_id
GROUP BY commissions.country_code, commissions.period
ORDER BY commissions.country_code, commissions.period
如果你有这个:
SELECT * FROM table
id, x
1, 'foo'
2, 'foo'
3, 'foo'
SELECT x, COUNT(*) as ct FROM table GROUP BY x
x, ct
'foo', 3
而且是 "correct"..
然后你这样做:
SELECT x, COUNT(*) as ct FROM table LEFT JOIN sometable ON table.x = sometable.y GROUP BY x
然后突然 "goes wrong":
x, ct
'foo', 7
因为有笛卡尔积;超过一行 sometable
与此行匹配。去掉 grouping/put a select * 看看:
SELECT * FROM table LEFT JOIN sometable ON table.id = sometable.otherid --GROUP BY x
id, x, otherid
1, 'foo', 1
1, 'foo', 1
1, 'foo', 1
2, 'foo', 2
2, 'foo', 2
2, 'foo', 2
3, 'foo', null
7 行,原因:
SELECT * FROM othertable
otherid
1
1
1
2
2
2
othertable
中的不止一行与 table
中的一行匹配
您需要限制您的连接,这样它就不会导致行的增加,或者在您执行连接之前将您的连接行分组到子查询中
如果突然不是所有行都必须匹配,则切换 JOIN 类型也会导致出现更多行,但这不会影响您在左侧计算 table 并添加的情况另一个通过左连接;只有笛卡尔乘积会影响这里
COUNT()
计算非 NULL
值的个数。您想要的最简单的解决方案是使用 COUNT(DISTINCT)
:
COUNT(DISTINCT commissions.id) AS count,
如果计数很小且维度很少(这里只有一维),这很有效。在其他情况下,您可能希望在加入之前聚合数据。
我在 postgresql 9.3 中使用 LEFT OUTER JOIN 时遇到计数聚合问题。
当我执行没有左外连接的标准语句时,它 returns 正确计数,在本例中为 3。当语句变得更复杂时,如下面的语句,它 returns 7 相反,这是不正确的。
只有部分 count() 聚合不正确,大多数是正确的。是什么原因造成的?我应该使用不同的联接吗?
SELECT country_code,
period,
COUNT(commissions.id) AS count,
SUM(commissions.total) AS total,
SUM(CASE WHEN commission_adjustments.is_bonus is True THEN commission_adjustments.total else 0 END) AS bonus
FROM commissions
LEFT OUTER JOIN commission_adjustments ON commissions.id = commission_adjustments.commission_id
GROUP BY commissions.country_code, commissions.period
ORDER BY commissions.country_code, commissions.period
如果你有这个:
SELECT * FROM table
id, x
1, 'foo'
2, 'foo'
3, 'foo'
SELECT x, COUNT(*) as ct FROM table GROUP BY x
x, ct
'foo', 3
而且是 "correct"..
然后你这样做:
SELECT x, COUNT(*) as ct FROM table LEFT JOIN sometable ON table.x = sometable.y GROUP BY x
然后突然 "goes wrong":
x, ct
'foo', 7
因为有笛卡尔积;超过一行 sometable
与此行匹配。去掉 grouping/put a select * 看看:
SELECT * FROM table LEFT JOIN sometable ON table.id = sometable.otherid --GROUP BY x
id, x, otherid
1, 'foo', 1
1, 'foo', 1
1, 'foo', 1
2, 'foo', 2
2, 'foo', 2
2, 'foo', 2
3, 'foo', null
7 行,原因:
SELECT * FROM othertable
otherid
1
1
1
2
2
2
othertable
中的不止一行与 table
您需要限制您的连接,这样它就不会导致行的增加,或者在您执行连接之前将您的连接行分组到子查询中
如果突然不是所有行都必须匹配,则切换 JOIN 类型也会导致出现更多行,但这不会影响您在左侧计算 table 并添加的情况另一个通过左连接;只有笛卡尔乘积会影响这里
COUNT()
计算非 NULL
值的个数。您想要的最简单的解决方案是使用 COUNT(DISTINCT)
:
COUNT(DISTINCT commissions.id) AS count,
如果计数很小且维度很少(这里只有一维),这很有效。在其他情况下,您可能希望在加入之前聚合数据。