postgresql中的多个左连接导致空结果

hwamh0ep  于 2023-03-01  发布在  PostgreSQL
关注(0)|答案(2)|浏览(223)

我在数据库中有3个表A、B和C,它们共享相同的列“name”。B具有属性“title”,而C具有属性“age”。
我期待着写一个SQL查询,我将不得不选择基于查询输入的所有内容,无论是B。标题,C。年龄或所有这些。
到目前为止我所尝试的,

SELECT * FROM A
LEFT JOIN B ON A.name = B.name
LEFT JOIN C ON A.name = C.name 
WHERE B.title = COALESCE($1, B.title)
AND C.age = COALESCE($2, C.age)

$1和$2来自外部程序。例如$1 =“Jones”和$2 = 12。
我从上面的查询中得到了一个空的结果。而且左连接似乎非常昂贵。有没有更快的方法来实现这一点,而不需要连接表。
如果$1为空,则查询将不具有来自B表的任何联接。我希望从A取回名称。如果$2为空,则查询将不联接C表,依此类推。如果两者都为空,则将返回A具有的任何内容。

jljoyd4f

jljoyd4f1#

WHERE子句的条件移至其各自的ON子句:

SELECT * 
FROM A
LEFT JOIN B ON B.name = A.name AND B.title = $1
LEFT JOIN C ON C.name = A.name AND C.age = $2;

如果$1null,则条件:

B.title = $1

将返回null和完整条件:

A.name = B.name AND B.title = $1

也将是null,这将导致B的所有行不匹配。
这同样适用于$2

cngwdvgl

cngwdvgl2#

如果给定名称不存在B,则条件B.title = COALESCE($1, B.title)将永远不匹配,无论$1的值如何,它都将计算为NULLC$2也是如此。
如果要忽略参数为NULL时的条件,则应编写

SELECT * FROM A
WHERE ($1 IS NULL OR (SELECT title FROM B WHERE B.name = A.name) = $1)
  AND ($2 IS NULL OR (SELECT age FROM C WHERE C.name = A.name) = $2)

你也可以试试

SELECT * FROM A
LEFT JOIN B USING (name)
LEFT JOIN C USING (name)
WHERE B.title IS NOT DISTINCT FROM COALESCE($1, B.title)
  AND C.age IS NOT DISTINCT FROM COALESCE($2, C.age)

或(海事组织更清楚地了解)

SELECT * FROM A
LEFT JOIN B USING (name)
LEFT JOIN C USING (name)
WHERE ($1 IS NULL OR $1 = B.title)
  AND ($2 IS NULL OR $2 = C.age)

但是您应该检查查询计划,因为它们似乎更难优化。

相关问题