PostgreSQL:如何从GROUP BY ROLLUP数据生成JSON

时间:2018-10-29 11:53:06

标签: json postgresql rollup

在将Group By ROLLUP(...)聚合到嵌套JSON中时,我需要一些帮助。

我的查询(及其结果)如下所示


查询#1

SELECT main, sub, subsub, count(*) FROM test 
GROUP BY ROLLUP(main, sub, subsub)
ORDER BY main, sub, subsub;

结果

| main | sub | subsub | count |
| ---- | --- | ------ | ----- |
| c    | c-1 | c-1-1  | 1     |
| c    | c-1 | c-1-2  | 1     |
| c    | c-1 |        | 2     |
| c    |     |        | 2     |
| d    | d-1 | d-1-1  | 1     |
| d    | d-1 |        | 1     |
| d    |     |        | 1     |
|      |     |        | 3     |

但我希望将其结果存储在下面的json

{
  c: {
    'total': 2,
    c-1: {
      'total': 2,
      'c-1-1': 1,
      'c-1-2': 1,
    }
  },

  d: {
    'total': 1,
    'd-1': {
      'total': 1,
      'd-1-1': 1
    }
  }
}

我已经尝试过json_build_object之类的东西,但是我无法操纵ROLLUP数据。非常感谢您的帮助!

这是link to the fiddle(PostgreSQL V10)

1 个答案:

答案 0 :(得分:0)

您需要分层查询:

with totals as (
    select main, sub, subsub, count(*) 
    from test 
    group by rollup(main, sub, subsub)
    order by main, sub, subsub
)

select jsonb_object_agg(main, sub) as main
from (
    select 
        main, 
        jsonb_object_agg(
            coalesce(sub, 'total'), 
            case when sub is null 
                then subsub->'total' 
                else subsub end
        ) as sub
    from (
        select 
            main, sub, 
            jsonb_object_agg(
                coalesce(subsub, 'total'), count
            ) as subsub
        from totals
        group by main, sub
        having main is not null
        ) s
    group by main
    ) m
where main is not null

db-fiddle.

不带cte的版本:

select jsonb_object_agg(main, sub) as main
from (
    select 
        main, 
        jsonb_object_agg(
            coalesce(sub, 'total'), 
            case when sub is null 
                then subsub->'total' 
                else subsub end
        ) as sub
    from (
        select 
            main, sub, 
            jsonb_object_agg(
                coalesce(subsub, 'total'), 
                count
            ) as subsub
        from (
            select main, sub, subsub, count(*) 
            from test 
            group by rollup(main, sub, subsub)
            ) subsub
        group by main, sub
        having main is not null
        ) sub
    group by main
    ) main
where main is not null