SQL Server存储过程不支持原生JSON参数,须用NVARCHAR(MAX)接收并先用ISJSON验证(需处理NULL),再用JSON_VALUE提取标量或OPENJSON+WITH解析结构化数据。

SQL Server 存储过程本身不支持 JSON 类型参数(截至 2026 年仍无原生 JSON 参数类型),必须用 NVARCHAR(MAX) 接收,再靠内置函数解析——这是所有后续操作的前提,别跳过验证直接 parse。
必须先用 ISJSON 验证输入合法性
传进来的字符串可能是空、乱码、或半截 JSON,ISJSON(@json_input) 返回 0 就说明不能往下走。它不报错,但后续 JSON_VALUE 或 OPENJSON 可能静默返回 NULL 或触发隐式转换异常。
IF ISJSON(@json_input) 1 BEGIN RAISERROR('Invalid JSON input', 16, 1); RETURN; END- 别只在开发环境测一次就删掉——生产中前端拼错字段名、少个逗号、多一个逗号,都让
ISJSON返回 0 -
ISJSON对NULL返回NULL(不是 0),所以得写成ISNULL(ISJSON(@json), 0) 1才保险
标量值提取优先用 JSON_VALUE,但注意路径和类型
想取 {"id": 123, "name": "Alice"} 里的 id,直接 JSON_VALUE(@json, '$.id') 最快。但它只认标量,遇到对象或数组就返 NULL,且默认输出是 NVARCHAR(4000)。
- 路径写错(比如写成
'$.ID'但实际是小写id)→ 返回NULL,不是报错 - 字段内容超长(如大段富文本)→ 必须显式转:
CAST(JSON_VALUE(@json, '$.desc') AS NVARCHAR(MAX)) - 嵌套路径如
'$.address.city',中间任意一层为NULL(比如address缺失),整列就是NULL,不是跳过
结构化解析必须用 OPENJSON + WITH,别裸调用
要从 [{"uid":1,"role":"admin"},{"uid":2,"role":"user"}] 拆成两行两列,就得用 OPENJSON(@json, '$') 配 WITH 子句。裸调 OPENJSON(@json) 只吐 key/value/type 三列字符串,你得自己 CAST 和判断类型,极易出错。
- 数组路径必须写准:
OPENJSON(@json, '$.items')→ 解析{"items":[...]};若直接传数组字符串N'[{"a":1}]',就用OPENJSON(@json)不带路径 -
WITH里声明的类型会自动转换并截断,比如uid INT '$.uid'遇到"uid": "abc"就变NULL,不会报错 - 字段缺失(某条记录没
role)→ 对应行该列为NULL,这是设计行为,不是 bug
兼容性不足时的兜底方案
如果数据库 compatibility_level OPENJSON 和 JSON_VALUE 根本不可用。此时唯一办法是升级兼容级别或改用 XML + FOR XML / sp_xml_preparedocument,但成本高、语法重。
- 查当前级别:
SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME() - 升级命令:
ALTER DATABASE [your_db] SET COMPATIBILITY_LEVEL = 130(需 db_owner 权限) - 若权限受限,只能把 JSON 解析逻辑移到应用层,存储过程只接收已拆解的参数列表
最易被忽略的是:同一段 JSON 在存储过程中反复被 OPENJSON 解析多次(比如循环里每次取一个字段),这会导致重复全文解析,CPU 直线上升。正确做法是一次展开、结果存临时表或 CTE,后续 SELECT 都基于它——JSON 解析是 CPU 密集型操作,不是 I/O 瓶颈。


















