必须先用ISJSON校验JSON有效性再解析,否则非法JSON会静默返回NULL;优先用OPENJSON WITH一次性提取多层字段,避免重复解析;数组遍历须用CROSS APPLY分层展开,不可用WHILE循环。

SQL Server 存储过程中解析嵌套 JSON 必须先 ISJSON 校验
不校验就直接用 JSON_VALUE 或 OPENJSON,遇到非法 JSON 会静默返回 NULL,查不出数据却找不到原因。这不是 bug,是设计行为。
-
ISJSON(@json)返回1才代表可安全解析;返回0或NULL时应直接RETURN或THROW,别往下走 - 常见陷阱:前端传空字符串
''、'null'(字符串)、或未转义的双引号,都会让ISJSON失败 - 别在存储过程里反复调用
ISJSON——只校验一次,后续所有解析都基于它通过的前提
提取多层嵌套字段优先用 OPENJSON WITH 而非嵌套 JSON_VALUE
比如要取 $.user.profile.name 和 $.order.items[0].price,写两个 JSON_VALUE 看似简单,但每次调用都会完整重解析整段 JSON,CPU 白烧,性能随字段数线性下降。
- 正确做法:
OPENJSON(@json) WITH (user_name NVARCHAR(100) '$.user.profile.name', first_item_price DECIMAL(10,2) '$.order.items[0].price') - 路径中任意一层为
null(如user缺失),对应列自动为NULL,无需额外判空 - 若字段可能超 4000 字符(如长文本描述),显式声明类型为
NVARCHAR(MAX),否则被无声截断
处理 JSON 数组必须用 CROSS APPLY 分层展开
想遍历 $.orders 下每个订单,再取每个订单里的 items,千万别用 WHILE + JSON_VALUE(@json, '$.orders[' + CAST(@i AS VARCHAR) + '].id') ——这既不可靠(索引越界不报错),又慢得离谱。
- 标准写法:先
OPENJSON(@json, '$.orders')展开订单,再对每行CROSS APPLY OPENJSON(value, '$.items')展开商品 - 注意:外层
OPENJSON的第二参数路径必须精确到数组,不能写成'$.orders.items'——那会把整个数组当对象解析,只出一行 - 如果数组本身是顶层结构(如
[{"id":1},{"id":2}]),调用OPENJSON(@json)即可,不加路径参数
JSON_VALUE 返回 NULL 不等于字段不存在
JSON_VALUE 对三种情况都返回 NULL:路径不存在、值为 JSON null、值为空字符串 ""。你无法区分它们,所以不能拿 WHERE JSON_VALUE(...) IS NULL 当“字段缺失”条件用。
- 判断字段是否存在,用
ISJSON(JSON_QUERY(@json, '$.field')) = 1(JSON_QUERY对不存在路径返回NULL,而ISJSON(NULL)是0) - 想区分空字符串和缺失,得靠
OPENJSON配WITH并设默认值,例如name NVARCHAR(50) '$.name' DEFAULT '' - 在
WHERE条件里裸用JSON_VALUE做等值匹配,没有计算列+索引的话,等于强制全表扫描解析,大数据量下直接卡死
JSON_VALUE 或 OPENJSON,SQL Server 都会从头解析整段字符串。所以宁可一次性用 OPENJSON WITH 拿出所有要用的字段,也别拆成七八个 JSON_VALUE 调用。


















