OPENJSON函数需指定WITH子句或默认模式,首参必须为nvarchar(max),路径表达式以$开头,嵌套对象需二次调用OPENJSON配合CROSS APPLY,大数据量下性能差且结构变更易致数据丢失。

OPENJSON函数的基本用法和必需参数
OPENJSON 是 SQL Server 2016+ 提供的原生 JSON 解析函数,它能把 JSON 字符串(尤其是数组)直接转成结果集。关键点在于:必须显式指定 WITH 子句或使用默认模式,否则只返回键名/类型/值三列,无法映射业务字段。
- 默认模式(不带
WITH)只适用于调试,返回key、value、type三列,且对嵌套结构支持弱 - 显式模式(带
WITH)才能按需提取字段,类型必须匹配——比如 JSON 中是字符串,WITH里写nvarchar(50);如果是数字,得写int或decimal(10,2) -
OPENJSON的第一个参数必须是nvarchar(max)类型,传入varchar或普通字符串字面量(如'[{"id":1}]')会隐式转换,但若含 Unicode 字符(如中文)而没加N前缀,可能乱码或截断
解析 JSON 数组时 WHERE 条件失效?注意路径表达式写法
常见错误是直接在 OPENJSON 外层加 WHERE 过滤字段,却发现没效果——本质是因为 OPENJSON 返回的是表值函数结果,字段名来自 WITH 定义,不是原始 JSON 键名。路径表达式写错也会导致取不到值。
- 路径表达式以
$开头,数组元素用[0]、[1]索引,对象属性用点号,如$.name、$[0].price - 如果 JSON 是纯数组(如
[{"a":1},{"a":2}]),WITH中路径写$.a是错的,应写a(相对路径),或显式写$.a但需配合AS JSON用法 - 想过滤某字段非空,得写
WHERE a IS NOT NULL,而不是WHERE $.a IS NOT NULL—— 后者语法错误
嵌套 JSON 对象怎么展开成多列?别漏掉 LATERAL JOIN
当 JSON 数组里每个元素还包含对象(如 "address":{"city":"Beijing","zip":"100000"}),直接在 WITH 里写 city nvarchar(20) '$.address.city' 可行,但若要展开多个层级或动态字段,就得嵌套调用 OPENJSON 并用 CROSS APPLY。
- SQL Server 不支持
JSON_VALUE在WITH中嵌套解析,所以address是对象时,不能靠单次OPENJSON提取全部子字段 - 正确做法是先主
OPENJSON提取顶层字段,再对address字段(假设已作为nvarchar(max)提出)二次调用OPENJSON,用CROSS APPLY关联 - 注意第二次
OPENJSON的输入必须是非 NULL 的 JSON 字符串,否则返回空结果——可用ISNULL(address, '{"city":"","zip":""}')防空
性能和兼容性陷阱:大数据量下 OPENJSON 很慢?
OPENJSON 是解释执行,没有索引,纯内存解析。10MB 以上 JSON 文本或上万条数组元素时,CPU 和内存压力明显上升,比等价的 XML 或 CSV 导入慢数倍。
- 避免在 WHERE 或 JOIN 条件中实时调用
OPENJSON——比如SELECT * FROM t WHERE EXISTS (SELECT 1 FROM OPENJSON(t.json_col) WITH (status int)),会导致每行都解析一次 - 高频查询场景,建议提前用触发器或作业把 JSON 拆解存到物理表,或用
computed column + PERSISTED缓存关键字段(需配合JSON_VALUE) - SQL Server 2017+ 支持
JSON_VALUE和JSON_QUERY作为计算列,但OPENJSON本身不能用于索引列定义
真正麻烦的不是语法,而是 JSON 结构变动时 WITH 子句必须同步改,而且类型不匹配不会报错,只会返回 NULL——这点很容易被忽略,上线后才发现数据丢失。


















