PostgreSQL string_agg,找不到值时的默认值

时间:2019-08-25 18:59:31

标签: sql postgresql

我有一张这样的桌子:

date    number      system_id
1       33.1        1
2       24.2        1
3       14.1        1
4       15.5        1
5       1113        1
1       4513        2
2       53.4        2
3       24.8        2
4       13.12       2
5       3333        2
我需要以这种格式转换的

[

[date 1, number in date 1 (of system_id 1), number in date 1 (of system_id 2), number in date 1 (of system_id 3), ...],
[date 2, number 2 (of system_id 1), number 2 (of system_id 2), number 2 (of system_id 3), ...],
[date 3, number 3 (of system_id 1), number 3 (of system_id 2), number 3 (of system_id 3), ...],
[date 4, number 4 (of system_id 1), number 4 (of system_id 2), number 4 (of system_id 3), ...],
[...]

]

使用此查询:

SELECT date,
STRING_AGG(number::character varying, ',' order by system_id asc) as n
FROM MyTable 
GROUP BY date

到目前为止,假设所有systems_ids的{​​{1}}数目都相同,那么效果很好。但是,事实并非如此。让我们向数据库添加一行:

dates

我的结果现在看起来像这样:

date    number      system_id
6       1234        2

这确实是个问题,因为我依靠数字的顺序来代表不同的systems_id。

[

[1, 33.1, 4513],
[2, 24.2, 53.4],
...
[6, 1234]

]

当没有要聚集的值时如何填充默认值?

我需要在结果中的第6行显示为["date", "system_id_1", "system_id_2"] [6, 0, 1234]或任何被认为是好的做法。尽管始终遵守顺序[6, NaN, 1234]是最重要的。

或者,可以跳过整行。为此,我可以致电

["date", "system_id_1", "system_id_2"]

并以某种方式排除SELECT date, STRING_AGG(number::character varying, ',' order by system_id asc) as n COUNT(date) as dates_count FROM MyTable GROUP BY date 不等于dates_count的所有行。但是如何?

1 个答案:

答案 0 :(得分:1)

您可以使用cross join生成行。然后引入数据并进行汇总:

select d.date,
       string_agg( coalesce(t.number::character varying, ''), ',' order by s.system_id asc) as numbers
from (select distinct system_id from mytable) s cross join
     (select distinct date from mytable) d left join
     mytable t
     on t.system_id = s.system_id and t.date = s.date
group by d.date;

我还建议您为此目的使用数组而不是字符串。

编辑:

或者,跳过不完整的行:

with ds as (
      select date,
             string_agg(number::character varying, ',' order by system_id asc) as n,
             count(*) as num_system_ids,
             max(count(*)) over () as max_num_system_ids
      from MyTable 
      group by date
     )
select ds.date, ds.n
from ds
where ds.num_system_ids = ds.max_num_system_ids;