JSON_ARRAYAGG是MySQL 8.0+聚合函数,需配合GROUP BY使用,用于将分组数据转为JSON数组;支持嵌套JSON_OBJECT,自动处理数据类型,但受group_concat_max_len限制。

MySQL 8.0+ 怎么用 JSON_ARRAYAGG 把分组数据转成 JSON 数组
直接说结论:JSON_ARRAYAGG 是 MySQL 8.0 引入的聚合函数,专为把多行数据聚合成一个 JSON 数组设计。它必须配合 GROUP BY 使用,不能单独用在普通查询里。
常见错误是把它当 JSON_OBJECT 那样单行构造用——比如写 SELECT JSON_ARRAYAGG(name) FROM users 却没 GROUP BY,结果只返回一个空数组或 NULL(取决于是否有数据)。
- 必须搭配
GROUP BY,哪怕你只想聚合全部数据,也得写GROUP BY ()(空分组,MySQL 8.0.23+ 支持)或加个常量如GROUP BY 1 - 参数只能是表达式,不支持直接传字段列表;想打包多个字段,得先用
JSON_OBJECT包一层,再喂给JSON_ARRAYAGG - 遇到
NULL值时,JSON_ARRAYAGG默认跳过(不是转成null),这点和GROUP_CONCAT类似,但行为不可配置
示例:查每个部门的员工姓名列表
SELECT dept, JSON_ARRAYAGG(name) AS members FROM employees GROUP BY dept;
PostgreSQL 里没有 JSON_ARRAYAGG,该用什么替代
PostgreSQL 没有同名函数,对应的是 json_agg() —— 注意大小写不敏感但习惯全小写,且功能更灵活些。
它不要求显式 GROUP BY,但实际仍需分组语义;如果漏写 GROUP BY,会把整张表聚成一个数组,容易误以为“成功”而线上出错。
-
json_agg()会保留NULL值(生成 JSON 的null),和 MySQL 行为不同 - 支持对子查询结果直接聚合,比如
json_agg(SELECT ...),但需用括号包裹子查询 - 若想控制键名顺序或排除空值,得提前在子查询里用
FILTER (WHERE ...)或CASE
示例:同样查部门员工列表,PostgreSQL 写法
SELECT dept, json_agg(name) AS members FROM employees GROUP BY dept;
JSON_ARRAYAGG 嵌套 JSON_OBJECT 时字段别名怎么处理
很多人想输出形如 [{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}],结果写出 JSON_ARRAYAGG(JSON_OBJECT('id', id, 'name', name)) 却发现字段名变成字符串字面量(即 key 是 'id' 而不是 id 的值)——这是误解了引号作用。
MySQL 中 JSON_OBJECT 的 key 必须是字符串字面量(带引号),value 才是表达式。所以正确写法就是带引号的 key + 不带引号的 value。
- key 写
'id'没问题,这是语法要求,不是 bug - 如果 value 是表达式(如
CONCAT(first_name, ' ', last_name)),直接写进去即可 - 别名不影响 JSON 输出结构,
AS members只是列名,JSON 内容由JSON_OBJECT决定 - 注意字段类型:数值、布尔、
NULL会被自动转成对应 JSON 类型;时间类型默认转成字符串(ISO 格式)
示例:带 ID 和姓名的对象数组
SELECT dept, JSON_ARRAYAGG(JSON_OBJECT('id', id, 'name', name)) AS members
FROM employees
GROUP BY dept;
性能和兼容性要注意的三个实际点
JSON_ARRAYAGG 看似简单,但在大数据量或复杂嵌套时容易拖慢查询,尤其当上游没索引或分组键区分度低的时候。
- 聚合前务必确认
GROUP BY字段有索引,否则可能触发临时表 + 文件排序,比普通GROUP BY更重 - 结果 JSON 大小受
group_concat_max_len影响(MySQL),虽然它名义上是为GROUP_CONCAT设的,但JSON_ARRAYAGG也共享该限制;超长会被截断,且无警告 - 低版本 MySQL(
真正上线前,拿真实数据量跑 explain,重点关注是否用到索引、是否出现 Using temporary;别只看开发环境几条测试数据就认为没问题。










