sql server 无原生json_arrayagg函数,须用子查询+for json实现数组聚合,如select dept_name, (select name,role from emp where dept_id=d.id for json auto) as staff_json from dept d group by d.id,dept_name。

SQL Server 不存在 JSON_ARRAYAGG 函数,直接写 JSON_ARRAYAGG 会报错“对象名 'JSON_ARRAYAGG' 无效”。你必须用 FOR JSON 配合子查询 + GROUP BY 实现等效效果,或改用 STRING_AGG 拼接后手动包 JSON 结构(不推荐)。
SQL Server 2016+ 正确做法:用 FOR JSON 在子查询中展开再聚合
SQL Server 不支持原生数组聚合函数,FOR JSON 是唯一可靠路径。它本质是把每组结果转成 JSON 数组字符串,不是生成真正的 JSON 类型值(注意类型是 NVARCHAR(MAX),不是 JSON)。
常见错误是试图在主查询里直接 SELECT ... FOR JSON 而没嵌套子查询,导致语法报错或结果错乱。
- 必须用子查询包裹分组逻辑,外层再加
FOR JSON;例如统计每个部门的员工列表: SELECT d.dept_name, (SELECT e.name, e.role FROM employees e WHERE e.dept_id = d.id FOR JSON AUTO) AS staff_json FROM departments d GROUP BY d.id, d.dept_name;-
FOR JSON AUTO自动推导结构,但字段名不能含点号(如e.name可,e.contact.email不行);需显式别名:e.contact_email AS [contact.email] - 空组返回
NULL,不是空数组[];若需强制返回空数组,得用ISNULL(..., '[]')包裹子查询 - 子查询里不能用
ORDER BY(除非加TOP 100 PERCENT),否则FOR JSON报错
为什么不用 OPENJSON 做聚合?
OPENJSON 是解析函数,不是聚合函数。它把 JSON 字符串“展开”成行,适合反向操作(比如把 JSON 数组炸开后做 GROUP BY),但无法把多行聚合成一个 JSON 数组。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
典型误用:SELECT JSON_VALUE(items, '$[0].id') FROM orders GROUP BY items —— 这只是取首元素,不是聚合。
- 想对 JSON 数组字段(如
orders.items)做统计,先用OPENJSON(items)展开,再GROUP BY原表主键,最后在外层用FOR JSON封装结果 - 漏掉
WITH子句时,OPENJSON返回key/value/type三列,无法直接聚合数值字段;必须写明路径:WITH (item_id INT '$.id', qty INT '$.qty') -
OPENJSON不自动验证 JSON 合法性;若字段含非法 JSON,查询直接报错,建议前置ISJSON(items) = 1过滤
SQL Server 2022+ 的新选项:JSON_OBJECTAGG 只适用于键值对,不适用于数组
JSON_OBJECTAGG 是 SQL Server 2022 引入的,但它只接受两个参数(key 和 value),输出是 JSON 对象 {"k1":"v1","k2":"v2"},**不能生成数组 [...]**。
如果你的数据天然是键值结构(如配置项 {"timeout":30,"retries":3}),可以用它;但面对订单明细这种数组结构,它完全不适用。
- 错误尝试:
SELECT JSON_OBJECTAGG('id', item_id) FROM OPENJSON(...) WITH (item_id INT '$.id')→ 返回对象,不是数组 - 强行模拟数组:用
STRING_AGG拼'[' + STRING_AGG(...) + ']',但需手动转义引号、处理NULL、兼容中文——极易出错,生产环境不建议 - 真正需要数组语义时,坚持用子查询 +
FOR JSON AUTO或FOR JSON PATH,后者控制力更强(可自定义根节点、包装字段)
最易被忽略的一点:SQL Server 的 JSON 功能全部依赖数据库兼容级别 ≥ 130,且 FOR JSON 在子查询中不能引用外部作用域的聚合别名(如 SELECT ..., (SELECT ... GROUP BY outer.id) FOR JSON 中的 outer.id 必须显式传入子查询 WHERE 条件)。跨层级引用失效是调试时最常见的卡点。










