我在PostgreSQL 13数据库中有两个表table_a
和table_b
,它们具有UUID主键列。table_a
有多个条目,而table_b
是空的(没有条目)。以下查询返回预期结果,即entry_count_a
大于0
:
SELECT COUNT(DISTINCT ta.uuid) AS entry_count_a FROM table_a ta
但是,以下查询将为两个entry_counts返回0
:
SELECT COUNT(DISTINCT ta.uuid) AS entry_count_a, COUNT(DISTINCT tb.uuid) AS entry_count_b FROM table_a ta, table_b tb
如何编写查询,使entry_count_a
包含正确的(预期的)值> 0
,而entry_count_b
是0
?
附加问题:为什么Postgres会有这样的行为?
5条答案
按热度按时间tjjdgumg1#
您当前的查询等效于以下查询:
当您在两个表之间应用笛卡尔积时,您要乘以它们的基数。你没有得到任何行,因为两个表中有一个的基数为0,因此0*n,对于任何n,总是0。
如果要正确显示这两个计数,可以使用两个子查询,如下所示:
检查演示here。
v64noz0r2#
您的查询将产生笛卡尔积表a x表b,因为您没有建立想要将它们关联起来的方式。通常,我们使用WHERE条件或JOIN子句。因此,如果B中有n行x B中有0行,则SQL语句的结果将是0行。在这种情况下,最简单的方法是运行两个单独的查询,每个表一个,或者像这样使用子选择:
zzlelutf3#
计数 0 是由于
FROM table_a ta, table_b tb
中的隐式CROSS JOIN
,其中一个空表抵消了另一个。正如其他答案已经指出的那样,加入是一种错误的方法。(除了手头的副作用,构建Cartesian product对于大表来说非常昂贵。而是运行两个单独的计数。
由于
uuid
是每个表中的PK,因此使用count(*)
:count(DISTINCT uuid)
将是一个很大的浪费,因为根据定义,uuid
是UNIQUE
。count(uuid)
仍然是浪费的,因为根据定义,该列也是NOT NULL
。Postgres有一个separate, faster implementation forcount(*)
,简单地计算行数。关于错位联接:
关于更快的计数(*):
xurqigkl4#
我现在使用的解决方法:
7uzetpgm5#
使用
CROSS JOIN
的另一种方法:或者简单地说:
Demo here