sql server 2022 使用 json 需设兼容级别≥130、参数用 nvarchar(max)、先 isjson() 校验再解析,批量用 openjson 一次性展开,字段缺失或嵌套需配合 json_query 和精确路径。

SQL Server 2022 支持 JSON 批处理存储过程,但必须用 OPENJSON 展开数组、用 NVARCHAR(MAX) 接收参数、且兼容级别不能低于 130 —— 否则函数直接不可用,不是报错而是“找不到对象”。
存储过程参数必须声明为 NVARCHAR(MAX)
SQL Server 没有原生 JSON 参数类型,所有 JSON 输入都得走字符串通道。用 VARCHAR 会丢中文、emoji 和 Unicode 控制字符;用 NVARCHAR(4000) 可能截断长字段(比如含 Base64 图片的 payload)。NVARCHAR(MAX) 是唯一安全选择。
- 错误写法:
@json_input VARCHAR(8000)→ 中文键名变成问号或乱码 - 正确写法:
@json_input NVARCHAR(MAX) - 若调用方传的是
XML或TEXT类型,必须先显式CAST(... AS NVARCHAR(MAX)),否则ISJSON()永远返回 0
必须先用 ISJSON() 校验再进解析逻辑
JSON_VALUE 和 OPENJSON 遇到非法 JSON 不抛异常,只静默返回 NULL 或空结果集。用户传错格式(比如少逗号、单引号代替双引号、BOM 头残留)时,存储过程看起来“执行成功”,实际没写入任何数据。
- 务必在开头加:
IF ISJSON(@json_input) 1 BEGIN RAISERROR('Invalid JSON input', 16, 1); RETURN; END - 别依赖
TRY...CATCH捕获 JSON 解析失败——这些函数本身不触发异常 - 调试时可加一句:
SELECT @json_input AS raw_json,粘贴到在线 JSON 校验器里快速定位格式问题
批量插入 JSON 数组要用 OPENJSON + INSERT ... SELECT
别用 WHILE 循环配合 JSON_VALUE(@json, '$[' + CAST(@i AS VARCHAR) + '].id') 模拟遍历——每次循环都重新全文解析,100 条记录就是 100 次完整 JSON 解析,CPU 白烧。
- 正确姿势:把整个 JSON 数组(如
N'[{"id":1,"name":"A"},{"id":2,"name":"B"}]')交给OPENJSON(@json_input)一次性展开成行集 - 配合
WITH子句映射字段:OPENJSON(@json_input) WITH (id INT '$.id', name NVARCHAR(50) '$.name') - 直接
INSERT INTO target_table SELECT ... FROM OPENJSON(...),让 SQL 引擎做集合操作 - 如果数组嵌套在对象下(如
{"items":[...]}),路径必须写全:OPENJSON(@json_input, '$.items')
字段缺失和嵌套对象要靠 JSON_QUERY 和路径精度控制
提取字段时,JSON_VALUE 只认标量值。路径指向对象或数组就返回 NULL,不是 bug 是设计如此;而 JSON_QUERY 保留原始结构,适合存档或转发。
- 想取
"tags": ["a","b"]→ 用JSON_QUERY(@j, '$.tags'),返回["a","b"](无额外引号) - 误用
JSON_VALUE(@j, '$.tags')→ 返回NULL,拼接新 JSON 时变成"tags": "NULL",前端JSON.parse()直接炸 - 中文键名必须转义:
'$.["收货地址"]',不能写'$.收货地址' - 深层嵌套(如
$.user.profile.phone)任一层为null,整条记录该字段就是NULL,这是预期行为,不是数据丢失
最常被忽略的其实是兼容级别和输入类型强制转换——哪怕你用的是 SQL Server 2022,默认数据库兼容级别可能还是 120(对应 SQL Server 2014),OPENJSON 函数根本不存在。查 SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME(),低于 130 就得先 ALTER DATABASE ... SET COMPATIBILITY_LEVEL = 130。










