我们在将数组分组到单个数组时遇到了问题。 我们希望将两个列中的值连接到一个单独的数组中,并聚合这些多行的数组。
给出以下输入:
| id | name | col_1 | col_2 |
| 1 | a | 1 | 2 |
| 2 | a | 3 | 4 |
| 4 | b | 7 | 8 |
| 3 | b | 5 | 6 |
我们想要以下输出:
| a | { 1, 2, 3, 4 } |
| b | { 5, 6, 7, 8 } |
元素的顺序很重要,应该与聚合行的id相关联。
我们尝试了array_agg函数:
SELECT array_agg(ARRAY[col_1, col_2]) FROM mytable GROUP BY name;
不幸的是,这句话引发了一个错误:
ERROR: could not find array type for data type character varying[]
似乎无法使用array_agg在group by子句中合并数组。
有什么想法吗?
答案 0 :(得分:6)
UNION ALL
你可以"反向转动"首先使用UNION ALL
:
SELECT name, array_agg(c) AS c_arr
FROM (
SELECT name, id, 1 AS rnk, col1 AS c FROM tbl
UNION ALL
SELECT name, id, 2, col2 FROM tbl
ORDER BY name, id, rnk
) sub
GROUP BY 1;
适合生成您稍后请求的值的顺序。 Per documentation:
汇总函数
array_agg
,json_agg
,string_agg
和xmlagg
, 以及类似的用户定义的聚合函数,生成 有意义的不同结果值取决于的顺序 输入值。默认情况下,此顺序未指定,但可以 通过在聚合调用中编写ORDER BY
子句来控制,如 见4.2.7节。或者,提供输入值 排序的子查询通常会起作用。
或您可以创建自定义聚合函数,如以下相关答案中所述:
Selecting data into a Postgres array
Is there something like a zip() function in PostgreSQL that combines two arrays?
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
,STYPE = anyarray
,INITCOND = '{}'
);
然后你可以:
SELECT name, array_agg_mult(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
或者,通常更快,而不是SQL标准:
SELECT name, array_agg_mult(ARRAY[col1, col2]) AS c_arr
FROM (SELECT * FROM tbl ORDER BY name, id) t
GROUP BY 1;
添加的ORDER BY id
(可以附加到此类聚合函数)可以保证您想要的结果:
{1,2,3,4}
{5,6,7,8}
或者您可能对此替代方案感兴趣:
SELECT name, array_agg_mult(ARRAY[ARRAY[col1, col2]] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
生成二维数组:
{{1,2},{3,4}}
{{5,6},{7,8}}
答案 1 :(得分:1)
select n, array_agg(c) as c
from (
select n, unnest(array[c1, c2]) as c
from t
) s
group by n
或更简单
select
n,
array_agg(c1) || array_agg(c2) as c
from t
group by n
解决新的订购要求:
select n, array_agg(c order by id, o) as c
from (
select
id, n,
unnest(array[c1, c2]) as c,
unnest(array[1, 2]) as o
from t
) s
group by n