json_value在update的where子句中会因非法json或路径不存在而报错,需配合isjson()和lax模式使用;不支持returning参数;返回值恒为nvarchar(4000),须显式转换;性能差,建议冗余关键字段或建persisted计算列索引。

JSON_VALUE 可以直接用在 UPDATE 的 WHERE 子句里,但必须注意:它不是“安全过滤器”,一旦 JSON 字段内容非法或路径不存在,整个语句会失败报错。
为什么 UPDATE WHERE JSON_VALUE(...) 会突然报错?
常见错误是 Msg 13609, Level 16, State 2, Line X: JSON text is not properly formatted. 或 Msg 13607, Level 16, State 2, Line X: Property cannot be found on the specified JSON path.。这不是你写错了 SQL,而是 JSON_VALUE 在 strict 模式下(默认)遇到无效 JSON 或缺失路径时直接抛异常——哪怕那行数据根本不在你要更新的范围内。
- SQL Server 不会对
WHERE条件做“短路预检”,它可能先尝试对所有候选行求值JSON_VALUE - 哪怕你加了
ISJSON(col) = 1,也不能完全避免:因为ISJSON只验证整体格式,不保证路径存在;而JSON_VALUE在找路径过程中发现任意位置有非法 JSON 就报错 - 尤其当列里混着旧数据、调试数据、空字符串或
NULL时,风险极高
安全写法:必须搭配 ISJSON 和 lax 模式路径
把路径显式写成 'lax $.field',并前置 ISJSON() 判断:
UPDATE Users SET status = 'archived' WHERE ISJSON(user_data) = 1 AND JSON_VALUE(user_data, 'lax $.isActive') = 'true' AND JSON_VALUE(user_data, 'lax $.role') = 'admin';
-
lax模式让JSON_VALUE在路径不存在或类型不匹配时不报错,而是返回NULL,这样= 'true'自然为 false,该行被跳过 -
ISJSON() = 1确保整段文本是合法 JSON,避免后续JSON_VALUE扫描时因格式错误崩溃 - 不要省略
ISJSON—— 即使业务上“应该都是 JSON”,生产环境总有意外
UPDATE 中 JSON_VALUE 的 RETURNING 参数没用
SQL Server 2022 不支持 JSON_VALUE(... RETURNING int) 这种写法。这个语法只在 SQL Server 2025(17.x)及以后版本才可用。你在 2022 里写 RETURNING 会直接报语法错误。
- 所有
JSON_VALUE返回值类型固定为nvarchar(4000),即使原 JSON 里是数字或布尔值 - 所以比较数字字段要写成
JSON_VALUE(..., '$.count') = '42',而不是= 42 - 想转类型?只能用
TRY_CAST(JSON_VALUE(...), int),但注意:如果JSON_VALUE返回NULL(比如路径不存在),TRY_CAST也返回NULL,不会出错
性能和索引注意事项
JSON_VALUE 在 WHERE 中无法利用普通索引,但 SQL Server 支持对它的计算列建索引:
ALTER TABLE Users ADD isActive AS JSON_VALUE(user_data, 'lax $.isActive'); CREATE INDEX IX_Users_isActive ON Users(isActive);
- 计算列必须用
lax路径,且不能包含变量或表达式 - 索引只加速等值查询(
= 'true'),范围查询(> 'a')效果有限 - 别忘了
PERSISTED——如果不加,每次查询都重新解析 JSON,索引就白建了 - 建完记得
UPDATE STATISTICS,否则优化器可能不用这个索引
真正容易被忽略的是:JSON 解析本身开销不小,尤其字段内容大或并发高时,JSON_VALUE 在 WHERE 里每行都执行一次,比普通列查询慢一个数量级。如果高频更新,优先考虑把关键字段冗余到普通列里。











