我的问题的小提琴可以在https://dbfiddle.uk/?rdbms=postgres_10&fiddle=e387589d446d9c9a952294f8c7a98494上找到。
我有简单的表格布局:
class
person: belongs to a class
room: belongs to a class
Run Code Online (Sandbox Code Playgroud)
以下查询选择嵌入了人员的所有类:
select class.identifier, array(select person.identifier from person where person.class_identifier = class.identifier) as persons
from class
order by class.identifier;
Run Code Online (Sandbox Code Playgroud)
在试验和学习更多有关相关子查询的信息时,我注意到可以通过用 aLEFT JOIN组合替换相关子查询来重写上面的查询GROUP BY:
select class.identifier, array_agg(person.identifier) as persons
from class
left join (
select person.identifier, person.class_identifier
from person
) as person
on class.identifier = person.class_identifier
group by class.identifier
order by class.identifier;
Run Code Online (Sandbox Code Playgroud)
请注意,我假设每个班级至少有一个人。如果没有,我可以添加coalesce()周围json_agg。
在我的第二种情况下,我将选择所有嵌入人员和房间的类。让我们首先以与上面第一个查询相同的方式编写:
select class.identifier, array(select person.identifier from person where person.class_identifier = class.identifier) as persons,
array(select room.identifier from room where room.class_identifier = class.identifier) as rooms
from class
order by class.identifier;
Run Code Online (Sandbox Code Playgroud)
这给出了预期的结果。
现在我想重复我之前所做的:引入LEFT JOINs。我的第一次尝试如下:
select class.identifier, array_agg(person.identifier) as persons
, array_agg(room.identifier) as rooms
from class
left join (
select person.identifier, person.class_identifier
from person
) as person
on class.identifier = person.class_identifier
left join (
select room.identifier, room.class_identifier
from room
) as room
on class.identifier = room.class_identifier
group by class.identifier
order by class.identifier;
Run Code Online (Sandbox Code Playgroud)
现在我得到了错误的结果。人或房间在输出数组中重复。我理解为什么会发生这种情况(我们正在对class、person和room之间的笛卡尔积进行分组,因此每个人都对每个房间重复,反之亦然),但我不知道如何进行。
我怎样才能在这里继续?是否可以开始替换SELECT子句中的多个相关子查询LEFT JOIN + GROUP BY,还是需要其他技巧?
您可以将不同的值聚合为:
array_agg(distinct person.identifier)
Run Code Online (Sandbox Code Playgroud)
但是,我不确定您为什么要加入这些子选择。您可以直接加入表,例如:
select class.identifier, array_agg(distinct person.identifier) as persons
, array_agg(distinct room.identifier) as rooms
from class
left join person
on class.identifier = person.class_identifier
left join room
on class.identifier = room.class_identifier
group by class.identifier
order by class.identifier;
Run Code Online (Sandbox Code Playgroud)
我还建议您为表使用别名。1 个或 2 个字母的缩写将使查询更易于阅读 (IMO):
select c.identifier, array_agg(distinct p.identifier) as persons
, array_agg(distinct r.identifier) as rooms
from class c
left join person p
on c.identifier = p.class_identifier
left join room r
on c.identifier = r.class_identifier
group by c.identifier
order by c.identifier;
Run Code Online (Sandbox Code Playgroud)
哦,欢迎来到该网站。第一个问题很好,包含代码和示例数据,做得很好。
| 归档时间: |
|
| 查看次数: |
998 次 |
| 最近记录: |