mysql 5.7+ 用 json_objectagg(key, value) 直接聚合为 json 对象,参数顺序不可颠倒,key 必须非 null 标量,value 可为 null;postgresql 用 jsonb_object_agg 支持键冲突覆盖;sql server 需 for json path 拼接;老旧版本推荐交由应用层解析。

MySQL 5.7+ 用 JSON_OBJECTAGG() 直接聚合为 JSON 对象
如果你用的是 MySQL 5.7 或更高版本,JSON_OBJECTAGG(key, value) 是最直接的解法:它把每组内的键值对聚合成一个 JSON 对象。注意参数顺序不能反——第一个是 key 字段(必须是标量、非 NULL),第二个是 value 字段(可为 NULL,会被转成 JSON null)。
常见错误是传入表达式导致 key 重复或非法字符,比如用中文列名没加别名、或 key 字段含空格/特殊符号未处理。稳妥做法是显式用 CAST 或 CONVERT 转成字符串,并确保 key 唯一可识别:
SELECT user_id, JSON_OBJECTAGG(
CONCAT('field_', field_name),
COALESCE(field_value, 'null')
) AS attrs_json
FROM user_attributes
GROUP BY user_id;
性能上,该函数在大分组时会比手动拼接快,但若 value 字段含二进制或大文本,可能触发临时磁盘表。建议提前 WHERE 过滤掉无意义记录。
PostgreSQL 用 JSONB_OBJECT_AGG() 处理键冲突更灵活
PostgreSQL 的 JSONB_OBJECT_AGG(key, value) 默认对重复 key 取最后一条,这点和 MySQL 不同。如果业务要求覆盖逻辑,不用额外处理;若需报错或合并数组,则得绕路:先 ARRAY_AGG(ROW(key, value)),再用 JSONB_OBJECT() + 自定义逻辑展开。
容易踩的坑包括:key 为 NULL 时整行被跳过(不报错)、value 为 jsonb 类型时自动嵌套,而 text 类型会被当字符串加引号。所以推荐统一 cast:
SELECT user_id,
JSONB_OBJECT_AGG(
key_name::TEXT,
COALESCE(value_raw::TEXT, 'null')::JSONB
) AS attrs
FROM user_config
GROUP BY user_id;
另外,JSONB_OBJECT_AGG 不支持 ORDER BY 内联排序,如需固定 key 顺序,得在外层用 JSONB_PRETTY() 或应用层处理。
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
SQL Server 2016+ 得靠 FOR JSON PATH 拼接再解析
SQL Server 没有原生键值聚合函数,主流做法是用 FOR JSON PATH 生成 JSON 数组,再用 STRING_AGG + 字符串替换模拟对象。但要注意:key 名不能含双引号或反斜杠,否则 JSON 格式会坏。
典型写法是先构造 "key":"value" 片段,再拼接并包上大括号:
SELECT user_id,
'{' + STRING_AGG(
'"' + REPLACE(key_col, '"', '\"') + '":' +
CASE WHEN value_col IS NULL THEN 'null'
ELSE '"' + REPLACE(value_col, '"', '\"') + '"'
END,
','
) + '}' AS attrs_json
FROM user_meta
GROUP BY user_id;
这种方法不校验 JSON 合法性,出错只能靠应用层捕获。若 value 含换行或控制字符,建议先用 FOR JSON PATH 转义一次再提取字段,而不是手写 REPLACE。
跨数据库兼容方案:先 GROUP_CONCAT / STRING_AGG 再交由应用解析
当数据库版本老旧(如 MySQL 5.6、PostgreSQL 9.4)或需强一致性校验时,硬凑 SQL JSON 容易翻车。更稳的路径是只做结构化聚合,把拼 JSON 的事交给应用层:
- 用
GROUP_CONCAT(CONCAT('"', key, '":"', value, '"'))(MySQL)或STRING_AGG(FORMAT('"%s":"%s"', key, value), ',')(PostgreSQL)生成键值对字符串 - 外层加
'{' || ... || '}'包裹,返回纯文本 - 应用收到后用标准 JSON 解析器加载,可捕获格式错误、重复 key、编码问题等
这招牺牲一点传输体积,换来的是可调试、可加日志、可 fallback 的确定性。尤其适合字段含义动态变化、value 类型混杂(数字/布尔/字符串)的场景。
真正麻烦的不是语法怎么写,而是 key 是否真能唯一标识属性、value 是否隐含需要类型推断的语义——这些 SQL 层根本看不到,得靠上游数据治理兜底。










