我有 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 项目的一部分,如果这有影响的话。
虽然强制执行引用完整性,并且查询所有 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)
,这应该是给定的。