sql server中处理json必须用json_value提取标量值或openjson解析数组/对象;前者路径须以$开头、返回null不报错,后者需with子句定义结构;索引优化须通过persisted计算列实现。

直接查 JSON 字段,必须用 JSON_VALUE 或 OPENJSON,不能用 WHERE column = 'xxx' 这种普通方式——SQL Server 不会自动解析字符串里的 JSON 结构。
JSON_VALUE 提取单个标量值(最常用)
适用于从 JSON 字符串里取一个字段,比如 "name"、"id" 或嵌套路径如 "address.city"。它只返回字符串、数字、布尔或 null,不支持数组或对象。
-
JSON_VALUE第二个参数是 JSON 路径表达式,必须以$开头,比如'$.name'、'$.skills[0]' - 如果路径不存在或 JSON 无效,返回
NULL(不是报错),所以 WHERE 条件里要小心空值漏判 - 不能用于超过 4000 字符的 JSON 字符串做索引查找——因为内部会截断,建议字段类型用
nvarchar(4000)存短 JSON,长的才用nvarchar(max) - 示例:
SELECT id, JSON_VALUE(doc, '$.name') AS name FROM Families WHERE JSON_VALUE(doc, '$.isRegistered') = 'true'
OPENJSON 配合 WITH 解析整个 JSON 对象或数组
当你需要把 JSON 数组展开成行,或一次性提取多个字段(尤其顶层是数组时),OPENJSON 是唯一可靠选择。它本质是把 JSON 变成一张临时表。
- 必须配合
WITH子句定义列名和类型,否则返回的是键/值对的通用结构,没法直接过滤 - 路径表达式在
WITH里写,比如name NVARCHAR(50) '$.name',不加$前缀也能工作,但显式写更清晰 - 如果原始 JSON 是数组(如
[{"a":1},{"a":2}]),OPENJSON默认按元素展开;如果是单个对象({"a":1}),需加AS JSON或用JSON_QUERY包一层再进 - 示例:
SELECT f.id, j.name, j.grade FROM Families f CROSS APPLY OPENJSON(f.doc) WITH (name NVARCHAR(50), grade INT) AS j WHERE j.grade > 5
ISJSON + 索引让查询变快
直接在 JSON 字段上建索引是无效的。想加速 JSON_VALUE 查询,得用「计算列 + 持久化 + 索引」三步走。
- 先加计算列:
ALTER TABLE Families ADD name_computed AS JSON_VALUE(doc, '$.name') PERSISTED - 再建索引:
CREATE INDEX IX_Families_name ON Families(name_computed) - 注意:计算列必须
PERSISTED才能索引;且ISJSON(doc) > 0应该作为 CHECK 约束加上,避免无效 JSON 污染计算列结果 - 兼容性级别必须 ≥ 130(SQL Server 2016 默认就是,但老数据库升级后可能没改)
别踩这些坑
常见报错或静默失败,基本都出在这几处:
- 字段类型用了
text或varchar:JSON 函数只认nvarchar(含nvarchar(max)),text已废弃且不支持 - 路径写错但没报错:比如写成
'$..name'(双点是 XPath 风格,SQL Server 不支持),实际要用'$.name';数组下标越界也只返回NULL,容易误判为数据缺失 - WHERE 中混用 JSON 和非 JSON 字段:比如
WHERE JSON_VALUE(doc, '$.id') = id,如果doc里id是字符串而表中id是 int,隐式转换会失败,最好显式转类型 - 忘了
ISJSON校验:如果业务允许往 JSON 字段插任意字符串,JSON_VALUE在无效 JSON 上始终返回NULL,WHERE 条件可能意外匹配所有坏数据
真正麻烦的不是语法,而是 JSON 字段里结构不一致——有人存 {"name":"a"},有人存 [{"name":"a"}],同一字段混合类型会让 OPENJSON 展开逻辑变得脆弱。上线前最好用 ISJSON 扫一遍数据分布。











