SQL Server存储过程使用JSON入参执行出现格式报错的排查
关于SQL Server存储过程接收JSON入参的问题解答
核心疑问确认
SQL Server 完全支持 将NVARCHAR(MAX)类型存储的JSON格式字符串作为存储过程输入参数,该用法是SQL Server 2016及以上版本内置JSON解析能力(OPENJSON、ISJSON等函数)的官方推荐实现方式,不存在参数类型不兼容的问题。
报错根因拆解
本次遇到的JSON格式解析错误、存储过程执行报错,是两部分问题叠加导致的:
1. 传入的JSON字符串本身格式非法(直接触发JSON解析报错)
报错提示的"Unexpected character '.' is found at position 480"是典型的JSON结构错位导致的偏移计算错误,并非真的在第480个字符位置存在非法点号:
- JSON结构中混入了多余的单引号:你编写的JSON闭合位置写为
}''},SQL解析器会把单引号识别为T-SQL字符串的边界,提前截断JSON内容,剩余零散字符被当成JSON的一部分继续解析,最终位置偏移后碰到点号就抛出错误。 - JSON嵌套对象的结构不匹配:
data字段对应的对象大括号没有和外层结构正确配对,中途换行时的引号书写不规范,导致解析器无法正确识别对象层级。 - 部分字段值本身不合法:比如
DueDate字段写了月份为13的日期值,就算JSON格式正确,后续类型转换也会失败。
2. 存储过程本身存在语法错误
就算JSON入参格式正确,原存储过程的写法也无法正常执行,存在多处语法漏洞:
OPENJSON的WITH子句中,RegionCode字段定义后漏写了列分隔的逗号,直接衔接了DueDate的定义。MERGE语句的UPDATE分支中,TARGET.[RegionCode]赋值语句多写了左括号未闭合。- 存储过程命名前后不一致:创建语句中写的存储过程名是
[warm].[stored _table](中间还带了多余空格),但实际调用时用的是[warm].[usp_upsert_warm_table],名称不匹配会导致存储过程找不到。
正确实现方案
1. 修正后的存储过程代码
-- 统一存储过程命名,和调用语句保持一致 CREATE PROCEDURE [warm].[usp_upsert_warm_table] ( @Json NVARCHAR(MAX) ) AS BEGIN SET NOCOUNT ON; BEGIN TRY -- 入参校验:提前判断JSON格式,抛出清晰错误 IF ISJSON(@Json) <> 1 BEGIN THROW 50001, '传入的JSON字符串格式非法,请检查结构', 1; END WITH JsonToTable AS ( SELECT * FROM OPENJSON (@Json) WITH ( [type] [nvarchar](100), [source] [nvarchar](38), [time] [nvarchar](28), [ID] [varchar](50) '$.data.ID', [RegionCode] [varchar](10) '$.data.RegionCode', -- 补全漏写的逗号 [DueDate] [datetime2](7) '$.data.DueDate', [SchedulStartDate] [datetime2](7) '$.data.SchedulStartDate' ) ) MERGE [warm].[table] AS TARGET USING JsonToTable AS SOURCE ON (TARGET.ID = SOURCE.ID) WHEN MATCHED THEN UPDATE SET -- 移除多余的左括号 TARGET.[RegionCode] = SOURCE.[RegionCode], TARGET.[DueDate] = [dbo].[ufn_cast_string_to_date](SOURCE.[DueDate]), TARGET.[SchedulStartDate] = [dbo].[ufn_cast_string_to_date](SOURCE.[SchedulStartDate]) WHEN NOT MATCHED THEN INSERT ( [SourceID] ,[ID] ,[RegionCode] ,[DueDate] ,[SchedulStartDate]) VALUES ( 1 ,SOURCE.[ID] ,SOURCE.[RegionCode] ,[dbo].[ufn_cast_string_to_date](SOURCE.[DueDate]) ,[dbo].[ufn_cast_string_to_date](SOURCE.[SchedulStartDate]) ); END TRY BEGIN CATCH -- 捕获错误并抛出,避免静默失败 THROW; END CATCH END
2. 修正后的存储过程调用代码
严格按照标准JSON规范编写入参,所有结构边界用双引号包裹、大括号成对闭合,避免混入单引号、多余符号:
DECLARE @return_value int EXEC @return_value = [warm].[usp_upsert_warm_table] @Json = N'{ "type" : "table", "source" : "informations", "time" : "2018-04-05T17:31:00Z", "id" : "A11-111-111", "data" : { "ID":"123-56", "RegionCode":"2", "DueDate":"2020-12-14T10:54:00", "SchedulStartDate":"2020-12-14T10:54:00" } }'
内容的提问来源于stack exchange,提问作者nada
相关产品推荐
相关产品推荐

