我怎样才能联合这两个相关的查询?
How can I unite these two related queries?
我有这个查询来检查一个人是否是客户或曾经是:
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
我还有另一个查询来获取位置:
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;
我如何将它们联合起来并在第一个查询中将人员位置显示为一行?
您将加入:
SELECT DISTINCT ON (ps.person_id) ps.person_id, ps.person.name,
(CASE WHEN ps.status = 'inactive' then 'Ex-Customer'
WHEN ps.status = 'active' then 'Customer'
END) AS account_status
FROM person_subscription ps INNER JOIN
person p
ON ps.person_id = p.id LEFT JOIN
(SELECT pl.person_id, STRING_AGG(pl.name, ';') as names
FROM person_location pl
GROUP BY pl.person_id
) pl
ON pl.person_id = p.id
ORDER BY ps.person_id, p.status ASC;
我不确定 WHERE
子句对于获取位置有何意义,但您也可以将其包含在子查询中。
如果我没听错,你可以使用横向连接:
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
如前所述,您最初的第一个查询缺少 order by
子句,这使得在有多个匹配项时将选择哪种订阅状态是不确定的。这在第二个子查询中翻译为 order by ps.??
,您需要将其替换为相关的列名。
另一个缺陷,在你问题的第二个查询中,string_agg()
的 order by
子句不是确定性的(组中的所有行都具有相同的 person_id
).我改为按位置名称排序,如果您愿意,可以将其更改为其他列。
我有这个查询来检查一个人是否是客户或曾经是:
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
我还有另一个查询来获取位置:
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;
我如何将它们联合起来并在第一个查询中将人员位置显示为一行?
您将加入:
SELECT DISTINCT ON (ps.person_id) ps.person_id, ps.person.name,
(CASE WHEN ps.status = 'inactive' then 'Ex-Customer'
WHEN ps.status = 'active' then 'Customer'
END) AS account_status
FROM person_subscription ps INNER JOIN
person p
ON ps.person_id = p.id LEFT JOIN
(SELECT pl.person_id, STRING_AGG(pl.name, ';') as names
FROM person_location pl
GROUP BY pl.person_id
) pl
ON pl.person_id = p.id
ORDER BY ps.person_id, p.status ASC;
我不确定 WHERE
子句对于获取位置有何意义,但您也可以将其包含在子查询中。
如果我没听错,你可以使用横向连接:
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
如前所述,您最初的第一个查询缺少 order by
子句,这使得在有多个匹配项时将选择哪种订阅状态是不确定的。这在第二个子查询中翻译为 order by ps.??
,您需要将其替换为相关的列名。
另一个缺陷,在你问题的第二个查询中,string_agg()
的 order by
子句不是确定性的(组中的所有行都具有相同的 person_id
).我改为按位置名称排序,如果您愿意,可以将其更改为其他列。