ARRAY_AGG 默认包含 NULL 值;需用 FILTER (WHERE col IS NOT NULL) 显式过滤,ORDER BY 必须写在函数内,空分组返回 NULL 而非空数组,应配合 COALESCE 使用。

ARRAY_AGG 会把 NULL 值也塞进去吗?
默认会。只要分组内某行的字段值为 NULL,它就会原样进入结果数组。这常导致后续用 UNNEST 或应用层解析时出错或逻辑异常。
实操建议:
- 用
ARRAY_AGG(col ORDER BY col) FILTER (WHERE col IS NOT NULL)显式过滤 —— 这是最干净的做法 - 若必须保留结构但不想传
NULL,可改用COALESCE(col, '')(注意类型需一致,比如都转成TEXT) - 别依赖
ARRAY_REMOVE(ARRAY_AGG(col), NULL):它只在 PostgreSQL 9.6+ 支持,且多一次遍历,性能略差
ORDER BY 在 ARRAY_AGG 里到底写在哪?
必须写在聚合函数内部,不是写在外部 GROUP BY 子句之后。写错位置会导致语法错误或排序失效。
正确写法是:ARRAY_AGG(col ORDER BY col DESC),而不是 ARRAY_AGG(col) ORDER BY col DESC(后者是给整个查询结果排序)。
常见错误现象:
-
Syntax error near ORDER:把ORDER BY放在括号外 - 数组顺序每次查询不一致:没加
ORDER BY,而ARRAY_AGG本身不保证顺序 - 想按另一列排序却写错字段:比如
ARRAY_AGG(name ORDER BY created_at)是合法的,但要确保created_at在GROUP BY中或为聚合列
聚合结果是空数组还是 NULL?
当分组无任何匹配行时,ARRAY_AGG 返回 NULL,不是空数组 {}。这点和 STRING_AGG 一致,但容易被误以为“没数据就该是空数组”。
应对方式:
- 需要空数组语义,统一用
COALESCE(ARRAY_AGG(col), ARRAY[]::text[])(类型需显式标注) - 如果聚合字段类型是
integer,就得写ARRAY[]::integer[],否则类型推导失败 - 在视图或函数中封装时,建议提前处理,避免调用方反复判空
和 STRING_AGG 混用时要注意什么?
两者行为差异大:一个返回数组,一个返回字符串;但更关键的是,STRING_AGG 默认跳过 NULL,而 ARRAY_AGG 不跳 —— 这常导致迁移或对比测试时结果不一致。
典型场景:
- 把旧
STRING_AGG(name, ', ')改成ARRAY_AGG(name)后,前端收到[null, "a", "b"],炸了 - 想兼容两种输出,可用
TO_JSONB(ARRAY_AGG(col))统一走 JSON 流程,但注意NULL在 JSON 中仍存在 - 性能上,
ARRAY_AGG内存开销略高,尤其大结果集;若只是为传输,考虑是否真需要数组结构,还是用STRING_AGG+ 应用层分割更轻量
ARRAY_AGG(ROW(a,b)) 或嵌套 ARRAY_AGG,调试起来得靠 pg_typeof() 和 ARRAY_LENGTH 反复验证。

















