snippetsqlMinor
How can I replace multiple correlated subqueries in the SELECT clause by LEFT JOINs?
Viewed 0 times
leftcanthereplacecorrelatedmultiplehowselectclausesubqueries
Problem
A fiddle for my question can be found on https://dbfiddle.uk/?rdbms=postgres_10&fiddle=e387589d446d9c9a952294f8c7a98494.
I have simple table layout:
The following query selects all classes with its persons embedded:
While experimenting and learning more about correlated subqueries, I noticed that the query above could be rewritten by replacing the correlated subquery with a
Please note that I made the assumption that each class has at least one person. If not, I could add
In my second case, I am going to select all classes with its persons and its rooms embedded. Let's first write in the same manner as the first query above:
This gives the expected results.
Now I want to repeat what I did before: introduce
```
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 pers
I have simple table layout:
class
person: belongs to a class
room: belongs to a classThe following query selects all classes with its persons embedded:
select class.identifier, array(select person.identifier from person where person.class_identifier = class.identifier) as persons
from class
order by class.identifier;While experimenting and learning more about correlated subqueries, I noticed that the query above could be rewritten by replacing the correlated subquery with a
LEFT JOIN combined with a 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;Please note that I made the assumption that each class has at least one person. If not, I could add
coalesce() around json_agg.In my second case, I am going to select all classes with its persons and its rooms embedded. Let's first write in the same manner as the first query above:
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;This gives the expected results.
Now I want to repeat what I did before: introduce
LEFT JOINs. My first attempt was as following:```
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 pers
Solution
You can aggregate over distinct values as:
However, I'm not sure why you are joining against these sub-selects. You can join directly against the tables like:
I would also suggest that you use an alias for your tables. 1- or 2- letter abbrevations will make the query easier to read (IMO):
Oh, and welcome to the site. A nice first question with code and sample data, well done.
array_agg(distinct person.identifier)However, I'm not sure why you are joining against these sub-selects. You can join directly against the tables like:
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;I would also suggest that you use an alias for your tables. 1- or 2- letter abbrevations will make the query easier to read (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;Oh, and welcome to the site. A nice first question with code and sample data, well done.
Code Snippets
array_agg(distinct person.identifier)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;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;Context
StackExchange Database Administrators Q#213575, answer score: 4
Revisions (0)
No revisions yet.