INNER JOIN 表上的 WHERE,但包括右表上匹配的所有行

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

我有 2 个具有一对多关系的表。表 A 包含“对象”,表 B 包含“组件”,它们具有相关的 id,我编写了一个查询来收集表 A 中的所有对象以及表 B 中的关联组件,如下所示:

SELECT A.*, ARRAY_AGG(B.*) FROM A INNER JOIN B USING(id) GROUP BY A.*

这满足了我的期望。

接下来我在 B 上有一个名为“type”的字段,可以是“X”、“Y”或“Z”。我想要执行与上面相同的查询,但过滤结果,以便仅包含具有关联组件(其中 B.type = 'X')的对象。此外,对于每个返回的对象,我仍然希望所有不是 B.type = 'X' 的关联组件。

我的第一次尝试是编写以下查询:

SELECT A.*, ARRAY_AGG(B.*) FROM A INNER JOIN B USING(id) WHERE B.type = 'X' GROUP BY A.*

但是此查询会删除类型不是 = 'X' 的组件。

有没有办法获取所有具有 type = 'X' 关联组件的对象,并且结果集返回每个对象的所有关联组件(无论类型如何)?

这是一个包含预期结果集的示例数据集:

答:

id
1
2
3
4

乙:

id 类型
1 X
1
1 Z
2
2 Z
3 X
4 Z
Result:
(1, [(1,X),(1,Y),(1,Z)]),
(3, [(3,X)])

这些查询是 SQLX Rust 项目的一部分,如果这有影响的话。

sql postgresql aggregate-functions sqlx
2个回答
0
投票

听起来您正在寻找

HAVING
子句。

SELECT A.*
     , ARRAY_AGG(B.*)F
FROM A JOIN B USING(id) 
GROUP BY A.*
HAVING 'X'=ANY(ARRAY_AGG(B.type));
--HAVING bool_or(B.type='X');

这是关于

bool_or()
和其他聚合的文档,这是关于
ANY
数组比较


0
投票

虽然强制执行引用完整性,并且查询所有 ID,但您甚至不必在查询中包含表 A:

SELECT id, array_agg(B.*)
FROM   B
GROUP  BY id
HAVING bool_or(true) FILTER (WHERE type = 'X');

关于聚合

FILTER
条款:

应该尽快 - 除非

type = 'X'
稀有
在这种情况下 - 假设
B(type, id)
是唯一的:

SELECT id, array_agg(B.*)
FROM  (SELECT id FROM B WHERE type = 'X') b1
JOIN   B USING (id)
GROUP  BY 1;

(type, id)
上有一个索引 - 可能是带有前导
UNIQUE
type
约束。
(更好的是,关于
(id) WHERE type = 'X'
的部分索引,但这可能太专业了。)
还有一个关于
(id)
,这应该是给定的。

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