在postgres中使用groupby子句时如何聚合json字段?

iyzzxitl  于 2021-08-13  发布在  Java
关注(0)|答案(1)|浏览(342)

在我的postgres数据库(v12.0)中有如下表结构

id | pieces | item_id | material_detail
---|--------|---------|-----------------
1  | 10     | 2       | [{"material_id":1,"pieces":10},{"material_id":2,"pieces":20},{"material_id":3,"pieces":30}]

2  | 20     | 2       | [{"material_id":1,"pieces":40}
3  | 30     | 3       | [{"material_id":1,"pieces":20},{"material_id":3,"pieces":30}

我使用groupby查询这个记录,如下所示

SELECT SUM(PIECES) FROM detail_table GROUP BY item_id HAVING item_id =2

用它我可以得到30块。但是我怎样才能从material\u detail group中按material\u id得到总件数呢。
我想要这样的结果

pieces |  material_detail
 -------| ------------------
  30    |  [{"material_id":1,"pieces":50},{"material_id":2,"pieces":20},{"material_id":3,"pieces":30}]

由于我来自mysql,我不知道如何在postgres中使用json字段来实现这一点。
注:物料明细栏为jsonb型。

zengzsys

zengzsys1#

你在两个不同的层次上聚合。我想不出一个解决方案不需要两个单独的聚合步骤。此外,要聚合物料信息,必须先取消项目id的所有数组,然后才能聚合每个物料id的实际工件值。然后必须将其聚合回json数组。

with pieces as (

  -- the basic aggregation for the "detail pieces"
  select dt.item_id, sum(dt.pieces) as pieces
  from detail_table dt
  where dt.item_id = 2
  group by dt.item_id

), details as (

  -- normalize the material information and aggregate the pieces per material_id
  select dt.item_id, (m.detail -> 'material_id')::int as material_id, sum((m.detail -> 'pieces')::int) as pieces
  from detail_table dt
    cross join lateral jsonb_array_elements(dt.material_detail) as m(detail)
  where dt.item_id in (select item_id from pieces) --<< don't aggregate too much    
  group by dt.item_id, material_id

), material as (

  -- now de-normalize the material aggregation back into a single JSON array
  -- for each item_id
  select item_id, jsonb_agg(to_jsonb(d) - 'item_id') as material_detail
  from details d
  group by item_id

)
-- join both results together
select p.item_id, p.pieces, m.material_detail
from pieces p
  join material m on m.item_id = p.item_id
;

在线示例

相关问题