Postgres 在 JSON 列之间聚合

问题描述 投票:0回答:1

我有一个 Postgres 数据库,其中包含模板和响应的表,每个模板定义它有多少行和项目,响应将项目放置在行中。我希望能够查询任何模板的所有响应中的“平均”位置的合并响应。

模板_帖子

id 数据
1 {"items":[{"id":0},{"id":1},{"id":2},{"id":3}],"rows":[{"id": "0","title":"第一行"},{"id":"1","title":"第二行"},{"id":"3","title":"第三行" },{"id":"4","title":"第四行"}]}
2 ...

response_post

id 模板_id [FK] 数据
1 1 {"filled_rows":[{"row_id":4,"item_ids":[0,1,3]}]}
2 1 {"filled_rows":[{"row_id":2,"item_ids":[2]}]}
3 1 {"filled_rows":[{"row_id":0,"item_ids":[1]},{"row_id":2,"item_ids":[2]},{"row_id":4,"item_ids": [3]}]}

在这种情况下,查询应返回以下合并响应:

{
  "filled_rows": [
    {
      "row_id": 0,
      "item_ids": [1]
    },
    {
      "row_id": 2,
      "item_ids": [2]
    },
    {
      "row_id": 4,
      "item_ids": [0,3]
    }
  ]
}

在有歧义的情况下,当某个项目在多行中出现相同次数时,应将其放置在这些行的第一行中。

sql json postgresql aggregate
1个回答
0
投票

这里需要几个级别的聚合。

  • 首先,在相关子查询中,将
    filled_rows
    item_ids
    分成单独的行。
  • item_id
    聚合并取最小值
    row_id
  • row_id
    聚合并获取
    item_ids
    的 JSON 数组。
  • 将整个过程聚合起来以获取一个 JSON 中的所有行
SELECT
  tp.id,
  r.result
FROM template_post tp
CROSS JOIN LATERAL (
    SELECT
      jsonb_build_object(
        'filled_rows', jsonb_agg(byRow.*)
      ) AS result
    FROM (
        SELECT
          byItem.row_id,
          jsonb_agg(byItem.item_id) AS item_ids
        FROM (
            SELECT
              MIN((r.value ->> 'row_id') ::int) AS row_id,
              i.value::int AS item_id
            FROM response_post rp
            CROSS JOIN jsonb_array_elements(rp.data -> 'filled_rows') r
            CROSS JOIN jsonb_array_elements_text(r.value -> 'item_ids') i
            WHERE rp.template_id = tp.id
            GROUP BY
              i.value::int
        ) byItem
        GROUP BY
          byItem.row_id
    ) byRow
) r;

db<>小提琴

© www.soinside.com 2019 - 2024. All rights reserved.