sql server存储过程无法直接接收json类型参数,必须使用nvarchar(max)接收json字符串并在内部用openjson解析;需确保unicode正确、兼容级别≥130、手动校验isjson,避免截断、乱码和解析失败。

JSON 数据本身不能直接作为原生参数类型传入存储过程——SQL Server 没有 JSON 类型参数,你只能用 nvarchar(max) 接收字符串形式的 JSON 文本,再在存储过程内部解析。
用 nvarchar(max) 接收 JSON 字符串是唯一可行方式
SQL Server 2016+ 不支持 json 作为参数类型(哪怕列支持 AS JSON 约束),所以存储过程签名里必须写成:
CREATE PROCEDURE usp_ProcessUserData
@jsonData nvarchar(max)
AS
BEGIN
-- 后续用 OPENJSON 解析
END
-
@jsonData必须是nvarchar(max),不能是varchar或固定长度(否则中文、特殊字符会截断或乱码) - 调用时需确保传入的是合法 JSON 字符串,比如
N'{"name":"Alice","age":30}'(注意前缀N) - 如果前端拼接 JSON,务必做 UTF-8 → UTF-16 转换(.NET 的
JsonConvert.SerializeObject默认输出正确;Node.js 的JSON.stringify需确认客户端编码)
在存储过程中用 OPENJSON() 解析并转为表结构
收到字符串后,不能直接用 JSON_VALUE 提取多层嵌套字段——它只返回单值;真正要“当表用”,得靠 OPENJSON() + WITH 子句。
例如解析用户数组:
SELECT *
FROM OPENJSON(@jsonData)
WITH (
name nvarchar(50) '$.name',
email nvarchar(100) '$.contact.email',
isActive bit '$.status.active'
);
-
OPENJSON()默认把顶层数组展开为行;如果是单个对象,加WITH是必须的,否则只返回 key/value 表(含key、value、type三列) - 路径表达式中字段名含空格或特殊字符,必须用双引号包裹,如
'$.["user id"]' - 若某字段缺失,对应列值为
NULL,除非显式指定DEFAULT(SQL Server 2022+ 支持,2016 不支持)
避免常见 JSON 解析失败:格式、权限与隐式转换
很多“解析为空”或“报错 invalid JSON”的问题,其实和语法无关,而是环境或类型陷阱:
- 传入的 JSON 字符串被自动转义:比如从 C# 的
SqlParameter.Value = JsonConvert.SerializeObject(obj)传入,但变量声明为varchar,导致 Unicode 字符损坏 → 一定用nvarchar参数和变量 -
OPENJSON()在 SQL Server 2016 中要求数据库兼容级别 ≥ 130(即 2016 默认值),低于此值会提示“找不到对象” - 如果 JSON 内容来自文件或外部系统,可能含 BOM 头(
0xEF,0xBB,0xBF)→ 用STUFF(@jsonData, 1, 3, '')清除(仅当确认开头是 BOM 时) -
JSON_VALUE()对非标量路径(如数组索引$.tags[0])返回NULL,不是报错;想取数组元素,必须先用OPENJSON()展开数组再查
最易被忽略的一点:你无法在存储过程参数里声明“这个 nvarchar(max) 必须是合法 JSON”——约束只能加在列上(ADD CONSTRAINT chk_is_json CHECK (ISJSON(@jsonData) = 1) 不生效,因为检查约束不作用于变量)。所有 JSON 校验必须手动加在存储过程开头,比如:
IF ISJSON(@jsonData) 1
THROW 50000, 'Invalid JSON format in @jsonData', 1;
否则后续 OPENJSON() 报错信息极不友好,只会说“无法解析”。











