gpt4 book ai didi

json - PostgreSQL 递归行到 JSONB 映射

转载 作者:行者123 更新时间:2023-11-29 13:15:20 25 4
gpt4 key购买 nike

这个问题最好用一个例子来解释。因此,如果您在 PostgreSQL 中有 2 个表 categoryevent,如下所示:-

create table category (
id integer primary key,
type varchar(255),
label varchar (255),
parent_id integer
);
insert into category (id, type, label, parent_id)
values (1, 'organisation', 'Google', null),
(2, 'product', 'Gmail', 1),
(3, 'organisation', 'Apple', null),
(4, 'product', 'iPhone', 3),
(5, 'product', 'Mac', 3);

create table event (
id integer primary key,
name varchar (255),
category_id integer
);
insert into event (id, name, category_id)
values (1, 'add', 4),
(2, 'delete', 5),
(3, 'update', 2);

如您所见,category 表非常动态,可以定义类别的层次结构。

我想要实现的是选择 event 表的条目并将其与类别连接,但将其展平为 JSON 结构。我可以使用以下查询来说明:-

select e.*, 
jsonb_build_object(
c1.type, c1.label,
c2.type, c2.label
) as categories
from event e
left join category c2 on c2.id = e.category_id
left join category c1 on c1.id = c2.parent_id

这将返回:-

+----+--------+-------------+------------------------------------------------+
| id | name | category_id | categories |
+----+--------+-------------+------------------------------------------------+
| 1 | add | 4 | {"organisation": "Apple", "product": "iPhone"} |
| 2 | delete | 5 | {"organisation": "Apple", "product": "Mac"} |
| 3 | update | 2 | {"organisation": "Google", "product": "Gmail"} |
+----+--------+-------------+------------------------------------------------+

但是,此方法仅在 event.category_id 列引用恰好具有 1 个父级(2 个级别)的子类别时才有效。实际上,我正在寻找的是生成 categories,无论 (a) 它是否没有父类别(即 1 级类别)或 (b) 是否有超过 1 个父类别(例如3 个级别)。例如,如果我将以下行添加到 eventcategory 表中:-

insert into category (id, type,           label,    parent_id) 
values (6, 'module', 'Mobile', 5), /* has 2 parents */
(7, 'organisation', 'AirBNB', null); /* has no parents */

insert into event (id, name, category_id)
values (4, 'event1', 6),
(5, 'event2', 7);

... 并从上方运行查询,它将返回:-

ERROR: argument 1: key must not be null
SQL state:

我的直觉是递归 CTE 可以解决这个问题。


更新1

 create or replace function category_array(category_parent_id int) returns setof jsonb as $$
select case
when count(x) > 0 then
jsonb_agg(f.x) || jsonb_build_object (
c.type, c.label
)
else jsonb_build_object (
c.type, c.label
)
end as category_pair
from category c
left join category_array (c.parent_id) as f(x) on true
where c.id = category_parent_id
group by c.id, c.type, c.label;

$$ language sql;

... 并使用此 SQL 调用...

select *, 
category_array(category_id)
from event;

...将返回以下...

+----+--------+-------------+--------------------------------------------------------------------------+
| id | name | category_id | categories |
+----+--------+-------------+--------------------------------------------------------------------------+
| 1 | add | 4 | [{"organisation": "Apple"}, {"product": "iPhone"}] |
| 2 | delete | 5 | [{"organisation": "Apple"}, {"product": "Mac"}] |
| 3 | update | 2 | [{"organisation": "Google"}, {"product": "Gmail"}] |
| 4 | event1 | 6 | [[{"organisation": "Apple"}, {"product": "Mac"}], {"module": "Mobile"}] |
| 5 | event2 | 7 | {"organisation": "AirBNB"} |
+----+--------+-------------+--------------------------------------------------------------------------+

非常接近,但还不够!

最佳答案

使用 concatenation operator ||构建累积的 jsonb 对象:

with recursive events as (
select
e.id, e.name, e.category_id as parent_id,
jsonb_build_object(c.type, c.label) as categories
from event e
left join category c on c.id = e.category_id
union all
select
e.id, e.name, c.parent_id,
categories || jsonb_build_object(c.type, c.label)
from events e
join category c on c.id = e.parent_id
)

select id, name, categories
from events
where parent_id is null
order by id;

请注意,查询不受循环依赖保护,因此您需要确保表中的所有路径都以空值结尾。

DbFiddle. 上测试查询


替代方案:

create or replace function get_categories(int) 
returns jsonb language sql as $$
select case
when parent_id is null then
jsonb_build_object (type, label)
else
jsonb_build_object (type, label) || get_categories(parent_id)
end as categories
from category
where id = $1
$$;

select id, name, get_categories(category_id)
from event
order by id;

DbFiddle.

关于json - PostgreSQL 递归行到 JSONB 映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49966443/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com