postgresql 按选定值将记录分组到不同的列中

vmdwslir  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(2)|浏览(244)

我有以下例子:

create table products (name text, id integer, type smallint, category integer);

insert into products values 
('apple', 23, 1, 1200),
('apple', 23, 1, 999),
('apple', 31, 2, 1200),
('apple', 23, 3, 1200),
('orange', 10, 1, 200),
('orange', 10, 2, 200),
('orange', 10, 2, 230),
('orange', 10, 3, 200),
('orange', 64, 1, 700),
('orange', 70, 2, 700);

DB FIDDLE
我希望结果是这样的:
| 姓名|type_1_3_id| type_2_id|
| - -----|- -----|- -----|
| 苹果|二十三|三十一|
| 橙子|{10,64}|{10,70}|
但是postgres强制我按列类型分组,这使得我的结果不是我想要的结果

select distinct name, 
case when type in (1,3) then array_agg(distinct id) end as type_1_3,
case when type = 2 then array_agg(distinct id) end as type_2
from products
group by 1, type
order by 1
dtcbnfnu

dtcbnfnu1#

array_agg函数中使用filter子句:

select name, 
 array_agg(distinct id) filter (where type in (1,3)) as type_1_3,
 array_agg(distinct id) filter (where type = 2) as type_2
from products
group by 1
order by 1

使用条件聚合array_agg(case when... then ... end)时,不匹配的行返回空值,而过滤器只聚合where子句中指定的行。
如果指定了FILTER,则只有filter_clause计算为true的输入行才被提供给聚合函数;其它行被丢弃。
Demo

dfddblmv

dfddblmv2#

由于您需要DISTINCT值,并且还需要排除空值,所以不能开箱即用ARRAY_AGG()。您可以单独筛选和聚合,然后加入这些聚合。
例如:

select coalesce(x.name, y.name) as name, x.a as type_1_3, y.a as type_2
from (
  select name, array_agg(distinct id) as a 
  from products where type in (1, 3) group by name
) x
full join (
  select name, array_agg(distinct id) as a 
  from products where type = 2 group by name
) y on y.name = x.name

结果:

name    type_1_3  type_2  
 ------- --------- ------- 
 apple   {23}      {31}    
 orange  {10,64}   {10,70}

请参见db<>fiddle上的运行示例。

相关问题