JSON_OBJECT / JSON_ARRAY 是什么
JSON_OBJECT 与 JSON_ARRAY 在查询里按行构造 JSON 值:前者把键值对拼成对象,后者把若干值拼成数组。它们让数据库直接把关系型结果转成接口需要的嵌套结构,省掉应用层循环拼装。MySQL 8.0 的函数名是 JSON_OBJECT / JSON_ARRAY,PostgreSQL 对应 json_build_object / jsonb_build_object 与 json_build_array / jsonb_build_array。构造结果本身是合法 JSON 类型,可以继续用 JSON_EXTRACT、-> 取值,也能直接交给客户端序列化输出。
基本信息
| 适用平台 | MySQL 8.0+ / PostgreSQL 9.4+ |
|---|---|
| MySQL 函数 | JSON_OBJECT(键, 值, ...)、JSON_ARRAY(值, ...) |
| PG 函数 | json_build_object / jsonb_build_object、json_build_array / jsonb_build_array |
| 参数规则 | JSON_OBJECT 的键与值必须成对出现,参数个数为奇数会直接报错 |
| NULL 处理 | 值为 SQL NULL 时输出 JSON null,键仍然保留,不会被省略 |
典型使用场景
- 接口直接返回嵌套结构:一次查询输出「用户 + 标签数组」,减少应用层拼装代码
- 把宽表的多个列封装成一个 JSON 列写入日志表或宽表,方便后续扩展字段
- 配合 JSON_ARRAYAGG / jsonb_agg 做分组聚合,生成「订单 + 明细」两层结构
- 给前端透传原始数据:只做结构转换,不做业务裁剪,降低后端耦合
- 与 JSON_TABLE 配合做行列互换,把固定列结构转成可检索的 JSON 行
MySQL 写法
MySQL 写法
SELECT JSON_OBJECT(
'id', u.id, # 键写字符串,值可以是列或字面量
'name', u.name,
'tags', JSON_ARRAY('vip', 'new') # 嵌套数组,直接放在值里
) AS user_json
FROM users u
WHERE u.id = 1;
SELECT JSON_OBJECT('a', NULL) AS demo; # 输出 {"a": null},键没有被丢PostgreSQL 写法
PostgreSQL 写法
SELECT jsonb_build_object(
'id', u.id,
'name', u.name,
'order_ids', jsonb_agg(o.id) # 聚合函数需要配合 GROUP BY 使用
) AS user_json
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id, u.name;
SELECT jsonb_build_array(1, 2, 3) AS arr; # -> [1, 2, 3]两库差异对照
| 对比项 | MySQL 8.0 | PostgreSQL |
|---|---|---|
| 构造对象 | JSON_OBJECT('k', v) | json_build_object / jsonb_build_object |
| 构造数组 | JSON_ARRAY(v1, v2) | json_build_array / jsonb_build_array |
| 重复键 | 同名键后写入的覆盖先写入的 | jsonb 去重、json 保留重复键 |
| 紧凑度 | 输出带空格,不压缩 | jsonb 紧凑输出,json 保留原有空白 |
| 取值方式 | JSON_EXTRACT 或 -> / ->> | -> 取 json/jsonb,->> 取文本 |
键名区分大小写,构造时写 'userId' 就得用 'userId' 去取,写成 'userid' 会返回 NULL 而不是报错。
构造出的 JSON 与聚合函数配合最常用:MySQL 用 JSON_ARRAYAGG / JSON_OBJECTAGG 把分组内的多行聚成一个数组或对象,PostgreSQL 用 jsonb_agg / jsonb_object_agg,聚合函数内部不能再用普通聚合,嵌套统计要先在子查询里算好。
不要用 CONCAT 手工拼 JSON 字符串:值里一旦出现引号、反斜杠或换行就会破坏结构,JSON_OBJECT / JSON_ARRAY 会按规范转义,务必用函数构造。