在单个SQL查询中返回json层次结构
我需要创建一个SQL查询(postgres 9.5.3),它返回一个分层json结果。这是我到目前为止写的代码在单个SQL查询中返回json层次结构,sql,postgresql,recursion,hierarchical-data,Sql,Postgresql,Recursion,Hierarchical Data,我需要创建一个SQL查询(postgres 9.5.3),它返回一个分层json结果。这是我到目前为止写的代码 WITH RECURSIVE q AS ( WITH c AS ( SELECT pc."Id", pc."Description" FROM "ProductCategories" pc WHERE pc."Active" = true ) SELECT pc, ARRAY[c] as "Children"
WITH RECURSIVE q AS (
WITH c AS (
SELECT pc."Id", pc."Description"
FROM "ProductCategories" pc
WHERE pc."Active" = true
)
SELECT pc, ARRAY[c] as "Children", ARRAY[pc."Id"] as "Path"
FROM "ProductCategories" pc
LEFT JOIN c ON pc."Id" = c."Id"
WHERE NULLIF(pc."ParentId", 0) IS NULL
AND pc."Active" = true
UNION ALL
SELECT pc_descendant, array_append(q."Children", c), q."Path" || pc_descendant."Id"
FROM q
JOIN "ProductCategories" pc_descendant ON pc_descendant."ParentId" = (q.pc)."Id"
LEFT JOIN c ON pc_descendant."Id" = c."Id"
WHERE pc_descendant."Active" = true
)
SELECT * FROM q
我无法创建分层对象子对象。对于这些结构
A
B
C
D
E
array\u append
函数似乎将任何子元素追加到单个数组中:
A.Children = [ {B}, {C}, {D} ] //for category A
我需要结构:
A.Children = [ {B, Children = [ {C, Children = [ {D} ] } ] } ]
如何更改查询以实现此目的?
关于我不确定这是否可能,至少以简单方便的方式
然而,使用“真”递归似乎很简单
下面是一个简单的例子:
create temp table t(id int, parent int, name text) on commit drop;
insert into t values
(1,null,'john'),
(2,1,'jane'),
(3,1,'jack'),
(4,2,'julian');
create or replace function build_family(p_parent int) returns setof jsonb as $$
select
case
when count(x) > 0 then jsonb_build_object('name', t.name, 'family', jsonb_agg(f.x))
else jsonb_build_object('name', t.name)
end
from t left join build_family(t.id) as f(x) on true
where t.parent = p_parent or (p_parent is null and t.parent is null)
group by t.id, t.name;
$$ language sql;
select jsonb_pretty(build_family) from build_family(null::int);
结果是
┌──────────────────────────────────────┐
│ jsonb_pretty │
├──────────────────────────────────────┤
│ { ↵│
│ "name": "john", ↵│
│ "family": [ ↵│
│ { ↵│
│ "name": "jane", ↵│
│ "family": [ ↵│
│ { ↵│
│ "name": "julian"↵│
│ } ↵│
│ ] ↵│
│ }, ↵│
│ { ↵│
│ "name": "jack" ↵│
│ } ↵│
│ ] ↵│
│ } │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│ 杰森布│
├──────────────────────────────────────┤
│ { ↵│
│ “姓名”:“约翰”,↵│
│ “家庭”:[↵│
│ { ↵│
│ “姓名”:“简”,↵│
│ “家庭”:[↵│
│ { ↵│
│ “姓名”:“朱利安”↵│
│ } ↵│
│ ] ↵│
│ }, ↵│
│ { ↵│
│ “姓名”:“杰克”↵│
│ } ↵│
│ ] ↵│
│ } │
└──────────────────────────────────────┘
我希望您可以根据您的数据对其进行调整
祝你好运。这真是太棒了-我喜欢这个优雅的解决方案,它真的展示了PostgreSQL的强大!我还将'family',jsonb_agg(f.x)
更新为'family',当jsonb_agg(f.x)!='[null]'::jsonb然后jsonb_agg(f.x)else'[]::jsonb end
返回“…“family”:…
而不是“…”family:[null]…
@bobmarksie这取决于IMO的要求。除您的建议外,我还更新了答案,以删除不必要的空“family”键。您好,在这种情况下,是否有人会在第一个和第二个递归循环中发生这种情况。是否可以在CTE中重新布线?(只是为了理解这个查询)。@JongzPuangput不,这是不可能的。函数使用表并自己递归调用。在一条语句中完成所有这些都是不可能的。抱歉,回答晚了。