在单个SQL查询中返回json层次结构

时间:2016-06-17 13:18:03

标签: sql postgresql recursion hierarchical-data

我需要创建一个返回分层json结果的SQL查询(postgres 9.5.3)。这是我到目前为止编写的代码

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

创建分层对象Children时遇到问题。对于这些结构

A
    B
        C
D
    E

array_append函数似乎将任何子元素附加到单个数组中:

A.Children = [ {B}, {C}, {D} ]    //for category A

我需要结构:

  A.Children = [ {B, Children = [ {C, Children = [ {D} ] } ] } ]

如何更改查询以实现此目的? 此致

1 个答案:

答案 0 :(得分:6)

不确定至少可以通过简单方便的方式实现。

然而,使用“true”递归似乎很简单。

这是一个简单的例子:

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"          ↵│
│         }                           ↵│
│     ]                               ↵│
│ }                                    │
└──────────────────────────────────────┘

我希望您可以根据自己的数据进行调整。

祝你好运。