JSON_AGG默认不过滤NULL,会将NULL值作为null元素加入数组;需用FILTER(WHERE col IS NOT NULL)显式过滤,或结合JSON_BUILD_OBJECT构造嵌套对象并配合ORDER BY保证顺序。

JSON_AGG 会把 NULL 值也塞进数组里
默认情况下,JSON_AGG 不过滤 NULL,只要某列值是 NULL,它就会生成 null 元素。比如:
SELECT JSON_AGG(name) FROM users WHERE id IN (1,2,3);如果其中一条记录的
name 是 NULL,结果里就会出现 null 字面量。
实际业务中多数情况要跳过空值,得配合 FILTER 或子查询:
- PostgreSQL 9.4+ 推荐用
FILTER (WHERE name IS NOT NULL) - 老版本可用子查询:
SELECT JSON_AGG(t.name) FROM (SELECT name FROM users WHERE name IS NOT NULL) t - 若想把
NULL转成空字符串再聚合,得先COALESCE(name, '')
嵌套对象要用 JSON_BUILD_OBJECT 配合 JSON_AGG
JSON_AGG 本身只做“扁平聚合”,没法直接产出带字段名的 JSON 对象。想得到 [{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}] 这种结构,必须先构造对象再聚合:
SELECT JSON_AGG(
JSON_BUILD_OBJECT(
'id', id,
'name', name,
'email', email
)
) FROM users GROUP BY dept_id;
注意点:
-
JSON_BUILD_OBJECT参数必须成对(key, value),奇数个参数会报错 - 如果某个字段可能为
NULL,JSON_BUILD_OBJECT仍会保留该 key 并设值为null;如需彻底剔除字段,得用CASE WHEN判断 - MySQL 没有
JSON_BUILD_OBJECT,得用JSON_OBJECT('id', id, 'name', name),语法稍异
GROUP BY 和 ORDER BY 的顺序影响结果稳定性
JSON_AGG 是聚合函数,但不保证内部元素顺序——除非显式加 ORDER BY:
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
SELECT dept_id, JSON_AGG(JSON_BUILD_OBJECT('name', name) ORDER BY name ASC) AS members FROM users GROUP BY dept_id;
没写 ORDER BY 时,不同执行计划或 PostgreSQL 版本可能导致数组顺序变化,前端依赖固定顺序时会出问题。
常见疏漏:
- 误以为
GROUP BY自带排序,其实不保证 - 在子查询里排序但外层没保留,导致聚合时顺序丢失
- 用
ORDER BY引用了未出现在SELECT中的列(如created_at),需确认该列在当前作用域可见
大结果集下 JSON_AGG 可能触发内存溢出
当单组数据超过几万行,JSON_AGG 会把整个中间结构加载到内存,容易触发 ERROR: out of memory 或拖慢查询。
缓解办法:
- 加
LIMIT控制每组最多聚合多少条:JSON_AGG(...) FILTER (WHERE row_number() OVER (PARTITION BY dept_id ORDER BY id) - 改用游标分批处理,避免单次聚合过大
- 确认是否真需要完整数组——有时前端只需要总数或前 N 条,用
COUNT(*)或ARRAY_AGG(...)[1:5]更轻量
别忘了检查 work_mem 设置,但调太高会影响并发能力。

















