postgresql 中多个左连接的空结果

问题描述 投票:0回答:2

我在数据库 A、B 和 C 中有 3 个表,它们共享同一列“名称”。 B 有一个属性“title”,C 有一个属性“age”。

我正在寻找一个 SQL 查询,我将不得不根据查询输入 B.title、C.age 或所有这些来选择 A 的所有内容。

到目前为止我尝试了什么,

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.

我从上述查询中得到一个空结果。 Left Join 似乎也很昂贵。有没有更快的方法可以在不加入表格的情况下实现这一目标。

如果 $1 为空,则查询将没有来自 B 表的任何连接。我想从 A 中取回名称。如果 $2 为空,则查询将不会加入 C 表,依此类推。如果两者都为空,它将返回 A 拥有的任何内容。

postgresql join left-join sql-null on-clause
2个回答
1
投票

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;

如果

$1
null
,则条件:

B.title = $1

将返回

null
和完整的条件:

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

也将是

null
,这将导致
B
的所有行都不匹配。

同样适用于

$2
.


1
投票

如果给定名称不存在

B
,则条件
B.title = COALESCE($1, B.title)
永远不会匹配,无论
NULL
的值如何,它的计算结果都是
$1
C
$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)

但是你应该检查那些查询计划,它们似乎更难优化。

© www.soinside.com 2019 - 2024. All rights reserved.