必须配合with子句才能返回结构化列;裸调openjson仅输出key/value/type三列,无法映射业务字段;路径以$.开头且区分大小写,需严格匹配json层级结构。

OPENJSON 函数必须配合 WITH 子句才能返回结构化列
直接调用 OPENJSON(不带 WITH)只返回三列:key、value、type,无法映射 JSON 字段到自定义列名。想把 [{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}] 变成两行两列的关系结果,必须显式声明结构。
常见错误是写成:
SELECT * FROM OPENJSON('[{"id":1,"name":"Alice"}]')
这只会输出原始键值对,不是你想要的表格。正确做法是:
SELECT * FROM OPENJSON('[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]')
WITH (
id INT '$.id',
name NVARCHAR(50) '$.name'
)
JSON 路径表达式中 $. 表示当前数组元素,不是根对象
在 WITH 子句里写的路径(如 '$.id')是相对于每个数组项的,不是整个 JSON 字符串的根。这点容易误解,尤其当 JSON 嵌套时。
比如解析这个结构:
[{"user":{"id":1,"info":{"name":"Alice"}}},{"user":{"id":2,"info":{"name":"Bob"}}}]
要提取 name,路径得写成 '$.user.info.name',而不是 '$.info.name' —— 因为每个数组元素本身是 {"user":{...}},不是 {"info":...}。
- 路径必须以
$.开头,不能省略 - 路径区分大小写,
'$.Name'和'$.name'是不同的 - 如果字段可能缺失,加
AS JSON或用ISNULL()包裹转换结果,避免NULL导致整行丢失
OPENJSON 不支持直接解析顶层非数组 JSON 对象
如果输入是单个对象(如 {"id":1,"name":"Alice"}),不是数组,OPENJSON 默认不会把它当一行处理——它会把对象展开成属性行,返回多行(每行一个 key-value)。这不是你想要的“转成一张表”。
解决方法只有两个:
- 把单对象包成数组:
OPENJSON('[' + @json + ']') - 或先用
JSON_VALUE提取字段,不走OPENJSON路线
注意:SQL Server 2016+ 要求输入必须是 NVARCHAR(MAX) 类型,传 VARCHAR 或短字符串会静默失败或截断。
性能和 NULL 处理容易被忽略
OPENJSON 是行集函数,内部会逐行解析 JSON,大数据量(>10k 元素)时明显慢于原生表连接。别在 WHERE 或 JOIN 中嵌套复杂 OPENJSON 调用,先存到临时表再处理更稳。
另外,JSON 字段类型不一致会导致转换失败:
-
id INT '$.id'遇到"id": "1"(字符串)会返回NULL,不是报错 - 想强制转换,得用
JSON_VALUE+TRY_CAST组合,例如:TRY_CAST(JSON_VALUE(value, '$.id') AS INT) -
WITH子句里没声明的字段,哪怕 JSON 里有,也不会出现在结果中
最常漏掉的是字符集:所有字符串列推荐用 NVARCHAR,否则中文会变问号;路径里也别混用单双引号,SQL Server 只认单引号。











