在SQL Server中处理JSON是一项基础技能,尤其是遇到多层嵌套的复杂JSON结构时,许多开发者会在OPENJSON使用上遇到难题。最常见的问题是字段无法正确映射,结果全部返回NULL。实际上,绝大多数NULL问题的根源并非数据本身,而是JSON路径书写错误或数据类型不匹配。

使用OPENJSON必须搭配WITH子句,否则只会返回key/value/type三列
当你执行OPENJSON(@json)却发现无法提取业务字段时,通常是因为WITH子句缺失或配置不当。没有WITH子句的OPENJSON始终只输出三列:key、value、type,无法直接使用SELECT name, age等操作。业务字段的映射完全依赖于在WITH子句中正确声明路径和数据类型。
常见错误:
WITH (id INT '$.id')误写为WITH (id INT 'id'),即遗漏了$.路径前缀。此时SQL Server不会报错,只会静默返回NULL,令人困惑。WITH (tags NVARCHAR(100) '$.tags')但tags实际为数组类型,结果同样为NULL。这种情况应改用JSON_QUERY或嵌套OPENJSON来处理。- JSON中的
"age": "25"本是字符串,却错误映射为INT类型,同样返回NULL而非报错。调试时可先用JSON_VALUE(@json, '$.age' ERROR ON ERROR)快速定位路径或类型问题。
嵌套数组需使用CROSS APPLY分层展开,不能依赖单层WITH直接指定路径
当遇到类似{"orders": [{"id":1,"items":[{"sku":"A"},{"sku":"B"}]}]}的多层结构时,切勿在顶层WITH中硬编码路径如sku NVARCHAR(20) '$.orders[0].items[0].sku'。这种方式只能提取第一个订单的第一个商品,无法与多行数据正确关联,导致结果混乱。
正确的做法是分层解析,具体步骤如下:
- 首先使用
OPENJSON(@json, '$.orders') WITH (order_id INT '$.id')展开订单记录。 - 然后对每个订单结果,通过
CROSS APPLY OPENJSON(value, '$.items') WITH (sku NVARCHAR(20) '$.sku')展开商品明细。注意:第二层OPENJSON中的value列源自第一层结果集的输出列,而非全局的@json变量。
处理可选字段或空数组时,路径错误会导致整行返回NULL,并非数据真正缺失
OPENJSON和JSON_VALUE在遇到路径错误、键不存在或类型不匹配时,都会静默返回NULL,而不给出任何提示。因此,当你发现大量NULL结果时,大概率不是数据缺失,而是路径定义有误。
排查建议:
- 首先使用
ISJSON(@json)验证输入JSON格式是否合法。 - 选取一两个关键字段,改用
JSON_VALUE(@json, '$.user.name' ERROR ON ERROR)测试路径是否正确。注意:ERROR ON ERROR仅适用于JSON_VALUE和JSON_QUERY函数。 - 对于空数组如
"someemptyproperty": [],当使用OPENJSON(@json, '$.someemptyproperty')时,结果将返回零行而非NULL。如需保留主记录,应使用LEFT JOIN或OUTER APPLY。
数据库兼容级别低于130时OPENJSON无法使用,务必提前检查
OPENJSON自SQL Server 2016起可用,但要求数据库兼容级别不低于130。若执行时出现提示'OPENJSON' is not a recognized built-in function name,无需惊慌,并非语法错误,而是当前环境不满足要求。
检查并升级的方式:
- 查看当前兼容级别:
SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME() - 执行升级命令:
ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL = 150(建议升级至150,兼容性更佳) - 注意:系统数据库如
master不可修改,仅业务数据库可操作。
嵌套层级越深、数组数量越多,CROSS APPLY链条就越长,越容易在某一层遗漏value引用或路径拼接错误。一个实用技巧是:每展开一层,立即使用SELECT TOP 5 *验证中间结果,这比最后发现全为NULL再反向排查要高效得多。
