postgresql LEFT JOIN ... WHERE返回的行数少于LEFT JOIN ON + AND

bpzcxfmw  于 2024-01-07  发布在  PostgreSQL
关注(0)|答案(1)|浏览(133)

看起来我完全无法理解这些查询结果(PostgreSQL DB):
a)仅在加入它们之后才进行过滤:

SELECT COUNT(*)
FROM apidata.info x
LEFT JOIN compdata.info a
    ON x.info = a.identifier
WHERE
    a.permit_id IS NULL
    AND a.identifier IS NULL;

个字符
B)仅在加入它们之前过滤的过滤器:

SELECT COUNT(*)
FROM apidata.info x
LEFT JOIN compdata.info a
    ON x.info = a.identifier
    AND a.permit_id IS NULL
WHERE a.identifier IS NULL;
count
--------
111981
(1 row)

的字符串
c)在加入它们之前和之后进行过滤:

SELECT COUNT(*)
FROM apidata.info x
LEFT JOIN compdata.info a
    ON x.info = a.identifier
    AND a.permit_id IS NULL
WHERE
    a.permit_id IS NULL
    AND a.identifier IS NULL;
count
--------
111981
(1 row)

的字符串
我不明白查询 Bc 怎么可能返回比查询 a 高**的计数。特别是我希望查询 c 返回的计数不会比查询 a 高,但它返回的计数与查询 B 完全相同。
这是在源表中具有数百万行的一些真实的数据(我已经概括了表和字段名称),但似乎我无法想象任何更简单的集合会产生类似的结果。
我在这里错过了什么?有人能提供一个更简单的例子吗?

ia2d9nvy

ia2d9nvy1#

这是一个奇怪的条件:x.info = a.identifier,然后是a.identifier IS NULL
=运算符不能处理空值。因此,where标识符为空的每一行都不会被连接。where条件,where a.identifier IS NULL因此是无用的,因为它总是空的。只有前导表x的数据。
这就是问题所在。
查询a的过滤方式更激进,因为

  • 首先,连接标识符不为空的所有compdata行(实际上匹配apidata中的某些内容)
  • 然后通过检查a.identifier IS NULL从结果中删除所有具有此类匹配的行。

对于B和c,你的过滤方式不那么激进:

  • 首先,你只连接那些有匹配的标识符 * 和 * 匹配的permit_id的行,所以这实际上比查询a的连接匹配的行少。对于其他行(比第一个查询中的多),compdata的列将为null,这些是你从这个查询中得到的行。
  • 然后筛选出具有匹配联接的所有行。

相关问题