I have this query to check if a person is a customer or have been:
SELECT DISTINCT ON (person_id) person_id, person.name, (CASE WHEN status = 'inactive' then 'Ex-Customer' WHEN status = 'active' then 'Customer' END) AS account_status FROM person_subscription INNER JOIN person ON person_subscription.person_id = person.id ORDER BY person_id, status ASC
And I have this other query to get the locations:
SELECT person_id, string_agg(name, ';' ORDER BY person_id) FROM person_location WHERE person_id IN (SELECT person_id FROM person_subscription WHERE status IS NOT NULL) GROUP BY person_id;
How can I unite them and show person location as a single row on the first query?
Advertisement
Answer
If I follow this correctly, you can use lateral joins:
select p.id as person_id, p.name, pl.*, ps.* from person p cross join lateral ( select string_agg(pl.name, ';' order by pl.name) as as person_locations from person_location pl where pl.person_id = p.id ) pl cross join lateral ( select case status when 'inactive' then 'ex-customer' when 'active' then 'customer' end as account_status from person_subscription ps where ps.person_id = p.id order by ps.?? limit 1 ) ps
As commented already, your original first query is missing an order by
clause, which makes it undefined which subscription status will be chosen where there are several matches. This translates as order by ps.??
in the second subquery, which you would need to replace with the relevant column name.
Another flaw, that time in the second query in your question, is that the order by
clause of string_agg()
is not deterministic (all rows in the group have the same person_id
). I ordered by location name instead, you can change that to some other column if you like.