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;
适用于生成您稍后请求的值的顺序。 The manual:
聚合函数array_agg、json_agg、string_agg和xmlagg,
以及类似的用户定义的聚合函数,产生
有意义的不同结果值取决于
输入值。默认情况下未指定此顺序,但可以
通过在聚合调用中编写 ORDER BY 子句来控制,如
如第 4.2.7 节所示。或者,从
排序的子查询通常会起作用。
我的大胆强调。
LATERAL 需要 Postgres 9.3 或更高版本。
SELECT t.name, array_agg(c) AS c_arr
FROM (SELECT * FROM tbl ORDER BY name, id) t
CROSS JOIN LATERAL (VALUES (t.col1), (t.col2)) v(c)
GROUP BY 1;
同样的结果。只需要一次通过桌子。
自定义聚合函数
或者您可以创建一个自定义聚合函数,就像这些相关答案中讨论的那样:
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(可以附加到此类聚合函数)保证了您想要的结果:
a | {1,2,3,4}
b | {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;
生成二维数组:
a | {{1,2},{3,4}}
b | {{5,6},{7,8}}
最后一个可以用 Postgres 9.5 或更高版本中的内置 array_agg() 替换(并且应该是,因为它更快!) - 增加了聚合数组的功能:
SELECT name, array_agg(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
同样的结果。 The manual:
输入数组连接成一维数组(输入
必须都具有相同的维度,并且不能为空或 null)
所以和我们自定义的聚合函数array_agg_mult()不完全一样;