【问题标题】:PostgreSQL: Getting STRING_AGG to respect the ordering from a CTEPostgreSQL:让 STRING_AGG 尊重 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 重写为子查询...?

【问题讨论】:

    标签: sql postgresql string-agg


    【解决方案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
    • 感谢您的关注。我也改变了我的答案。最良好的祝愿。
    猜你喜欢
    • 1970-01-01
    • 2018-06-27
    • 1970-01-01
    • 2020-12-25
    • 2019-09-13
    • 1970-01-01
    • 2017-08-01
    • 2016-02-29
    • 2013-12-24
    相关资源
    最近更新 更多