动态SQL存储过程执行报错varchar值转int类型失败怎么解决?
报错根因
- 动态SQL拼接触发了隐式类型转换:你在拼接
@sql变量时,直接把int类型的@C___operation、@formfieldId和字符串用+连接,SQL Server的优先级规则会尝试把字符串转为int类型做数值计算,而不是做字符串拼接,直接触发你遇到的转换报错。 - 错误混用
sp_executesql的传参能力:你已经通过sp_executesql声明了要传入参数,完全不需要把参数值硬拼到SQL语句里,硬拼不仅会触发类型错误,还存在SQL注入风险,同时binary(10)类型的@C___start_lsn直接转字符串拼接后的格式也不符合SQL语法要求,就算解决int转换问题后续也会报错。 - 缺少表名校验:如果传入的表名不存在,
@ActualTableName会是NULL,执行动态SQL也会抛出不易排查的报错。
修复后的存储过程代码
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[sp_GetFormFieldCDC] ( @formfieldId INT, @C___operation INT, @C___start_lsn binary(10), @tablename NVarchar(255) ) AS BEGIN SET NOCOUNT ON DECLARE @ActualTableName AS NVarchar(255) SELECT @ActualTableName = QUOTENAME( TABLE_NAME ) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @tablename -- 增加表名校验,报错更直观 IF @ActualTableName IS NULL BEGIN RAISERROR('传入的表名不存在',16,1) RETURN END DECLARE @sql AS NVARCHAR(MAX) -- 仅表名做拼接,所有过滤条件用参数占位,不硬拼值 SELECT @sql = 'SELECT * FROM ' + @ActualTableName + ' WHERE __$start_lsn = @C___start_lsn AND __$operation = @C___operation AND ID = @formfieldId;' -- 传参执行,不需要传入@tablename,因为已经拼接到SQL语句中 EXEC sp_executesql @SQL, N'@formfieldId INT, @C___operation INT, @C___start_lsn binary(10)', @formfieldId, @C___operation, @C___start_lsn END GO
通用排查技巧
后续遇到动态SQL相关报错时,可以在执行EXEC sp_executesql前加一行PRINT @sql,把拼接完成的SQL语句打印出来,直接就能看到拼接后的语法是否符合预期,快速定位错误点。
内容的提问来源于stack exchange,提问作者Morks
相关产品推荐
相关产品推荐

