我有一个 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]
}
]
}
在有歧义的情况下,当某个项目在多行中出现相同次数时,应将其放置在这些行的第一行中。
这里需要几个级别的聚合。
filled_rows
和 item_ids
分成单独的行。item_id
聚合并取最小值 row_id
。row_id
聚合并获取 item_ids
的 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;