PostgreSQL:让 STRING_AGG 尊重 CTE 的排序
Posted
技术标签:
【中文标题】PostgreSQL:让 STRING_AGG 尊重 CTE 的排序【英文标题】:PostgreSQL: Getting STRING_AGG to respect the ordering from a CTE 【发布时间】:2021-06-07 15:30:22 【问题描述】:我正在创建一份报告,显示员工的前团队以及他们离开的日期,并汇总到报告中的单个字段中。这在一定程度上有效:
WITH "most_recent_leave_dates" AS (
SELECT
staff_id, -- alphanumeric string
team,
MAX(date_left) AS "most_recent_date_left"
FROM team_membership
WHERE date_left IS NOT NULL
GROUP BY staff_id, team
-- I thought ordering this CTE would do it, but no
ORDER BY staff_id, most_recent_date_left DESC
)
SELECT
staff_id,
STRING_AGG(
DISTINCT CONCAT(team, ' until ' || most_recent_date_left),
CHR(10) -- separate by newline
) AS "teams"
FROM most_recent_leave_dates
GROUP BY staff_id
https://www.db-fiddle.com/f/jZCcKRWNV8vLJUFsa6kq7/2
但STRING_AGG
是按字母顺序对术语进行排序。我希望它们按most_recent_date_left
排序。我该怎么做?
documentation 声明:
或者,提供来自排序子查询的输入值将 通常工作。
我是否必须将 CTE 重写为子查询...?
【问题讨论】:
【参考方案1】:ORDER BY
在 CTE 中毫无意义。您可以将ORDER BY
作为STRING_AGG()
的一部分:
SELECT staff_id,
STRING_AGG(CONCAT(team, ' until ' || most_recent_date_left),
CHR(10)
ORDER BY most_recent_date_left DESC
) AS "teams"
FROM most_recent_leave_dates
GROUP BY staff_id;
【讨论】:
我发誓我试过了,它坚持我ORDER BY
整个CONCAT
声明。谢谢,这样更好。
@JackDeeth。 . . ORDER BY
不能与DISTINCT
一起使用,因此它可能会产生错误。干杯。
也许问题标题应该是“当我唯一的调试反馈是来自 SAP BusinessObjects 内部的一个小弹出窗口时,我如何编写 SQL 并保持理智”……可能必须使用具有代表性的虚拟数据。
“ORDER BY
在 CTE 中毫无意义”仅当 CTE 的顺序被 STRING_AGG
中的另一个 ORDER BY
覆盖时,对吧?在STRING_AGG
中没有DISTINCT
,我可以通过仅订购CTE 来订购结果:db-fiddle.com/f/jZCcKRWNV8vLJUFsa6kq7/3
@JackDeeth。 . .它有时有效并不能保证。我建议你仔细阅读这个问题的公认答案:dba.stackexchange.com/questions/130552/…。【参考方案2】:
只需从外部查询中删除不同的内容,如下所示(我认为您不需要这个)。您的数据在 cte 中已按 staffid 和 most_recent_date_left 排序。
架构 (PostgreSQL v9.6)
CREATE TABLE "team_membership" (
staff_id text,
team text,
date_left date
);
INSERT INTO team_membership VALUES
('aaaa', 'B team', '2019-01-01'),
('aaaa', 'A team', '2021-01-01'),
('aaaa', 'C team', '2020-01-01'),
('aaaa', 'A team', '2018-01-01');
查询 #1
WITH "most_recent_leave_dates" AS (
SELECT
staff_id,
team,
MAX(date_left) AS "most_recent_date_left"
FROM team_membership
WHERE date_left IS NOT NULL
GROUP BY staff_id, team
)
SELECT
staff_id,
STRING_AGG(
CONCAT(team, ' until ' || most_recent_date_left),
CHR(10) order by most_recent_date_left desc
) AS "teams"
FROM most_recent_leave_dates
GROUP BY staff_id;
staff_id | teams |
---|---|
aaaa | A team until 2021-01-01 C team until 2020-01-01 B team until 2019-01-01 |
View on DB Fiddle
【讨论】:
根据另一个答案,不能保证 CTE 的排序......所以ORDER BY
属于STRING_AGG
。
感谢您的关注。我也改变了我的答案。最良好的祝愿。以上是关于PostgreSQL:让 STRING_AGG 尊重 CTE 的排序的主要内容,如果未能解决你的问题,请参考以下文章
PostgreSQL合并多行数据为一行,string_agg函数
使用 PostgreSQL 13 上的另一列使用 string_agg 订购 DISTINCT?
PostgreSql 聚合函数string_agg与array_agg