如何聚合子查询中的多行?

How to aggregate multiple rows from subquery?

我想为每个 prod_id 获取 chd_id 的数组, 下面的查询有效,但仅适用于 limit 1 我想要准确的结果,但有多个行

select 
    prod_id,
    array_agg((select * from jsonb_array_elements(products.prod_prop) limit 1)->>'chd_id')
from products
group by prod_id
limit 10

当前结果:

products.prod_prop 的原始值为

[{"val": ["xxx"], "chd_id": 25812}, {"val": ["yyy"], "chd_id": 2342}]

没有 limit 1 我得到 ERROR: more than one row returned by a subquery used as an expression

你可以在table中使用CROSS JOIN和使用jsonb_array_elements()函数生成的子查询:

SELECT p.prod_id, array_agg(j.e->>'chd_id') AS chd_id
  FROM products p
 CROSS JOIN jsonb_array_elements(prod_prop) j(e)
 GROUP BY prod_id

我认为您需要使用横向连接来执行此操作:

select prod_id,
       array_agg(t.chd_id)
from products p
  left join lateral (
    select e ->> 'chd_id' as chd_id
    from jsonb_array_elements(p.prod_prop) as t(e)
  ) t on true
group by prod_id
limit 10;

如果 prod_prop 个值为空,则需要外连接

显然,JSONB 中的数据有时是数组,有时是普通对象。如果所有“普通对象”确实都是空值,您可以使用以下方法解决该问题:

select prod_id,
       array_agg(t.chd_id) filter (where t.chd_id is not null)
from products p
  left join lateral (
    select e ->> 'chd_id' as chd_id
    from jsonb_array_elements(nullif(p.prod_prop,'{}')) as t(e)
  ) t on true
group by prod_id
limit 10;

如果您确实在该列中混合了普通对象和数组,则需要采用不同的方法:

select prod_id,
       array_agg(t.chd_id) filter (where t.chd_id is not null)
from products p
  left join lateral (
    select e ->> 'chd_id' as chd_id
    from jsonb_array_elements(case jsonb_typeof(p.prod_prop)
                                when 'array' then p.prod_prop
                                else '[]'
                              end) as t(e)
  ) t on true
group by prod_id
limit 10;

Online example