SQL Server 2022 不支持 JSON_AGG,应使用 JSON_OBJECTAGG(键值对聚合)或 FOR JSON(行转JSON数组);前者仅接受key/value两参数、自动去重key、不支持排序;后者需子查询配合GROUP BY,空结果返回NULL,须显式处理。

JSON_AGG 在 SQL Server 2022 中并不存在 —— 它是 PostgreSQL 的函数,SQL Server 用的是 JSON_OBJECTAGG 和 FOR JSON,二者用途和行为完全不同。
别把 PostgreSQL 的 JSON_AGG 当成 SQL Server 的功能
很多开发者从 PostgreSQL 切到 SQL Server 后直接搜 JSON_AGG,结果发现报错 Invalid object name 'JSON_AGG'。这不是版本问题,而是根本没这个函数。SQL Server 2022 的标准聚合 JSON 工具是 JSON_OBJECTAGG(键值对映射)和 FOR JSON(整行转 JSON 数组/对象),必须按场景选对。
需要聚合为键值对时,用 JSON_OBJECTAGG
JSON_OBJECTAGG 只接受两个参数:key 和 value,输出是一个 JSON 对象(不是数组)。它天然适合“分组后每个组生成一个 key→value 映射”的场景,比如按部门统计人数:
SELECT JSON_OBJECTAGG(department, cnt) AS dept_counts FROM ( SELECT department, COUNT(*) AS cnt FROM employees GROUP BY department ) t;
注意点:
-
JSON_OBJECTAGG会自动去重 key:如果同一 key 出现多次,只保留最后一次的 value - key 必须是标量(不能是 JSON 对象或数组),且不能为 NULL;NULL key 会导致整个聚合返回 NULL
- 不支持排序或过滤子句,如想控制顺序,得在子查询里先
ORDER BY再聚合(但实际输出顺序不保证) - 若需嵌套结构(比如每个部门下再聚合员工姓名列表),不能靠
JSON_OBJECTAGG单层完成,得套FOR JSON
需要聚合为 JSON 数组时,必须用 FOR JSON + GROUP BY
SQL Server 没有原生的“多行 → JSON 数组”聚合函数,FOR JSON 是唯一可靠方式,但它不能出现在子查询或聚合表达式中,只能挂载在顶层 SELECT 末尾。所以要实现类似 JSON_AGG(ROW_TO_JSON(...)) 的效果,得这样写:
SELECT department, (SELECT name, hire_date FROM employees e2 WHERE e2.department = e1.department FOR JSON PATH, WITHOUT_ARRAY_WRAPPER) AS staff FROM employees e1 GROUP BY department;
关键约束:
- 子查询必须加括号,否则语法错误
-
WITHOUT_ARRAY_WRAPPER仅当子查询单行结果时安全;若可能多行,去掉它,结果就是带方括号的 JSON 数组字符串 - 子查询里不能用聚合函数(如
COUNT)而不配GROUP BY,否则报错is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause - 性能上,每组触发一次子查询,大数据量时比 PostgreSQL 的
JSON_AGG开销高;SQL Server 2022 的列存储索引 + 内存优化表可缓解,但逻辑无法绕过
空结果或 NULL 值处理容易被忽略
SQL Server 对空集和 NULL 的处理很“诚实”,但容易引发前端解析失败:
-
FOR JSON遇到空子查询返回NULL,不是[];可用ISNULL(..., '[]')补默认值 -
JSON_OBJECTAGG遇到全 NULL key 或空输入,直接返回NULL,不是{};需用CASE WHEN COUNT(*) > 0 THEN JSON_OBJECTAGG(...) END包一层 - 字段含特殊字符(如点号、斜杠)作 key 时,
JSON_OBJECTAGG不转义,会导致非法 JSON;应提前用REPLACE处理或改用FOR JSON PATH配别名(如name AS 'user.name')
最易漏的一点:所有 JSON 输出默认是 NVARCHAR(MAX),但如果你把它塞进非 Unicode 字段或没设对客户端连接的 collation,中文会变成乱码或 uXXXX 编码 —— 这和函数本身无关,却是上线后第一波报错来源。

















