Skip to content
Advertisement

How can I unite these two related queries?

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.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement