array_agg是标准聚合函数,用于将分组后多行的标量值聚合成数组,支持ORDER BY和DISTINCT;ARRAY_CAT仅拼接两个现有数组,非聚合函数,不能跨行使用。

array_agg 是聚合数组字段的正解,ARRAY_CAT 不是聚合函数
想把多行数据聚合成一个数组,必须用 array_agg;ARRAY_CAT 是二元操作符(类似 ||),只用于拼接两个已存在的数组,不能跨行聚合。误用 ARRAY_CAT 会报错:ERROR: function array_cat(anyarray, anyarray) does not exist(除非显式安装 intarray 扩展且类型匹配)。
常见错误场景:看到 “数组拼接” 就直奔 ARRAY_CAT,结果发现它不接受分组上下文,也没办法处理空值或 NULL 行。
-
array_agg是标准聚合函数,天然支持GROUP BY、ORDER BY、DISTINCT(需配合子查询) -
ARRAY_CAT(a, b)只能写在SELECT列表或WHERE中,作用域仅限单行,无法替代聚合逻辑 - 若真要拼接多个数组列(如
tags1和tags2字段),可用tags1 || tags2,但这是行内运算,不是聚合
string_agg 不能直接处理数组字段,必须先展开
如果字段本身是数组类型(比如 text[]),直接对它用 string_agg 会报错:ERROR: function string_agg(text[], unknown) does not exist。因为 string_agg 只接受标量(scalar)输入,不接受数组。
正确做法是先用 unnest 把数组展开成行,再喂给 string_agg:
SELECT string_agg(elem, ', ') FROM (SELECT unnest(tags_array) AS elem FROM posts WHERE id = 123) t;
注意两点:
- 若原数组含
NULL,unnest默认跳过;需要保留NULL占位就得加WITH ORDINALITY并手动处理 - 若想控制拼接顺序,必须在子查询里加
ORDER BY elem,string_agg(... ORDER BY ...)对unnest后的结果无效(语法虽允许,但实际不生效)
array_agg 的排序和去重必须显式声明
array_agg 默认完全不保序,即使源数据已按某字段排序,聚合后数组元素顺序仍是不确定的。去重也不存在内置参数——array_agg(DISTINCT x) 是合法语法,但仅在 PostgreSQL 9.5+ 支持,且只对非数组输入有效;对数组字段本身去重仍需 unnest → DISTINCT → array_agg 套路。
典型安全写法:
-- 有序 + 去重(针对标量字段) SELECT (SELECT ARRAY(SELECT DISTINCT UNNEST(array_agg(name ORDER BY name)) ORDER BY 1)) FROM users WHERE dept = 'eng'; <p>-- 针对数组字段去重(如 tags_array 是 text[] 类型) SELECT ARRAY( SELECT DISTINCT elem FROM (SELECT unnest(tags_array) AS elem FROM posts) t ORDER BY elem );
-
array_agg(x ORDER BY x)的ORDER BY必须写在括号内,写在外面(GROUP BY ... ORDER BY x)只影响最终结果行序,不影响数组内部顺序 - 含
NULL时,默认排最前;要放最后得写ORDER BY x NULLS LAST - 多字段排序支持,如
array_agg(name ORDER BY dept, salary DESC)
性能与兼容性:并行聚合可用,但嵌套 unnest 拖慢大表
PostgreSQL 10+ 对 array_agg 和 string_agg 支持并行聚合,大数据量下可显著提速。但一旦引入 unnest + 子查询组合(尤其去重或跨数组操作),优化器大概率退回到串行执行,且内存占用陡增。
真实瓶颈常出现在这里:你以为只是“加个 DISTINCT”,实际触发了临时哈希表 + 排序 + 重建数组三阶段,比纯 array_agg 慢 3–5 倍。
- 优先用
array_agg(DISTINCT x ORDER BY x)(单字段、非数组)代替unnest套路,更简洁且可能走索引 - 避免在
WHERE条件未过滤前就unnest大数组字段,容易 OOM - 若字段是固定小数组(如
text[3]),考虑用COALESCE展开各下标而非unnest,减少中间行数

















