Postgresql jsonb_agg 子查询排序

And*_*rao 10 postgresql json subquery

如何对使用 json 聚合的子查询的结果进行排序?

如果我有这样的架构:

CREATE TABLE plans( id integer NOT NULL, name character varying(255));
CREATE TABLE plan_items ( id integer NOT NULL, plan_id integer NOT NULL, expected_at date, status integer);
Run Code Online (Sandbox Code Playgroud)

我正在通过子查询在 json 列上聚合 plan_items 结果。像这样:

SELECT
  plans.id,
  plans.name,
  jsonb_agg((SELECT pi_cols FROM 
       (SELECT plan_items.id, plan_items.expected_at, plan_items.status) pi_cols
      )) AS plan_items_data
FROM
  plans
  INNER JOIN plan_items ON plan_items.plan_id = plans.id
GROUP BY
  plans.id,
  plans.name
ORDER BY plans.id;
Run Code Online (Sandbox Code Playgroud)

JSON 聚合按预期工作,并为我提供所需的结果。好的。但我无法对结果进行排序。

我试过了:

  jsonb_agg((SELECT pi_cols FROM 
       (SELECT plan_items.id, plan_items.expected_at, plan_items.status ORDER BY plan_items.expected_at) pi_cols
      )) AS plan_items_data
Run Code Online (Sandbox Code Playgroud)

并且:

  jsonb_agg((SELECT pi_cols FROM 
       (SELECT plan_items.id, plan_items.expected_at, plan_items.status) pi_cols ORDER BY pi_cols.expected_at
      )) AS plan_items_data
Run Code Online (Sandbox Code Playgroud)

但这些都没有解决。

有任何想法吗?

Ine*_*ego 12

正如Abelisto 所建议的,只需使用带有 ordering的简单聚合表达式

jsonb_agg(plan_items ORDER BY plan_items.expected_at) AS plan_items_data
Run Code Online (Sandbox Code Playgroud)


kli*_*lin 3

使用所需的排序顺序连接表,并使用横向连接来选择列jsonb_agg()

select s.plan_id id, name, jsonb_agg(pi_col)
from (
    select p.id plan_id, p.name, pi.id, expected_at, status
    from plans p
    join plan_items pi 
    on p.id = pi.plan_id
    order by p.id, expected_at
    ) s,
lateral (
    select plan_id id, expected_at, status
    ) pi_col
group by 1, 2
order by 1;
Run Code Online (Sandbox Code Playgroud)

上面的查询似乎比选择列表中带有子查询的查询更自然、更灵活(在大多数情况下更快一些)。然而,为了获得更好的性能,您还应该应用 Abelisto 的建议:

select s.plan_id id, name, json_agg(pi_col order by pi_col.expected_at)
from (
    select p.id plan_id, p.name, pi.id, expected_at, status
    from plans p
    join plan_items pi 
    on p.id = pi.plan_id
    ) s,
lateral (
    select plan_id id, expected_at, status
    ) pi_col
group by 1, 2
order by 1;
Run Code Online (Sandbox Code Playgroud)