如何在存储过程LOG_ListTab_Key_SP的@RefValue参数中传入多个值?
如何在存储过程LOG_ListTab_Key_SP的@RefValue参数中传入多个值?
看来你想要通过给@RefValue传多个值来批量查询、提升效率对吧?原来的写法只能支持单个值,因为存储过程里的动态SQL用的是=做判断,所以得从参数传递方式和SQL逻辑两方面调整,我给你两种实用的解决方案:
方案一:用逗号分隔的字符串传多个值(快速改造)
这种方式不需要修改存储过程的参数定义,只需要调整动态SQL里的判断逻辑,适合快速落地需求:
1. 调用存储过程时的写法
把多个值用逗号分隔,直接传给@RefValue:
DECLARE @return_value int EXEC @return_value = [dbo].[LOG_ListTab_Key_SP] @Tab = N'CAD_USERS', @RefField = N'usucod', @RefValue = N'204,205' -- 多个值用逗号分隔 SELECT 'Return Value' = @return_value
2. 修改存储过程里的动态SQL逻辑
找到存储过程中拼接WHERE条件的部分,把原来的=判断改成IN,同时用REPLACE把逗号分隔的字符串转成IN需要的格式:
原来的代码片段:
set @sel = @sel + ' FROM [dbo].[log_tab] with (nolock) where logtab = '+ char(39)+ @tab + char(39) + ' and logReg.value(' + char(39) set @sel = @sel +'(//@' + @filter + ')[1]' + char(39) + ', ' + char(39) + @filterTip + char(39) + ') = ' + char(39) + @RefValue + char(39) -- ... 中间省略 ... set @sel = @sel + ' where '+ @filter + ' = '+ @RefValue
修改后:
set @sel = @sel + ' FROM [dbo].[log_tab] with (nolock) where logtab = '+ char(39)+ @tab + char(39) + ' and logReg.value(' + char(39) set @sel = @sel +'(//@' + @filter + ')[1]' + char(39) + ', ' + char(39) + @filterTip + char(39) + ') IN (' + REPLACE(@RefValue, ',', ''',''') + ')' -- ... 中间省略 ... set @sel = @sel + ' where '+ @filter + ' IN (' + REPLACE(@RefValue, ',', ''',''') + ')'
REPLACE(@RefValue, ',', ''',''')会把'204,205'转换成'204','205',刚好符合IN的语法要求。
方案二:用表值参数传多个值(更安全规范)
如果担心逗号分隔的方式有SQL注入风险,或者值本身可能包含逗号,推荐用表值参数的方式,这也是SQL Server中批量传值的标准做法:
1. 先创建一个用户定义表类型
CREATE TYPE dbo.IdList AS TABLE (Id NVARCHAR(100)) GO
2. 修改存储过程的参数定义
把原来的@RefValue参数改成表值类型:
ALTER PROCEDURE [dbo].[LOG_ListTab_Key_SP] @Tab NVARCHAR(100), @RefField NVARCHAR(100), -- 假设你的@filter变量就是这个参数,根据实际情况调整 @RefValue dbo.IdList READONLY -- 改成表值参数 AS BEGIN -- 保留原来的其他逻辑,只修改WHERE条件部分 DECLARE @sel NVARCHAR(MAX) = '' DECLARE @filter NVARCHAR(100) = @RefField -- 这里根据你原来的变量定义调整 DECLARE @filterTip NVARCHAR(100) = 'varchar(100)' -- 假设你的filterTip是这个,根据实际情况调整 DECLARE @cmpDat NVARCHAR(100) = 'GETDATE()' -- 假设你的cmpDat是这个,根据实际情况调整 -- 拼接log_tab的查询部分 set @sel = @sel + ' FROM [dbo].[log_tab] with (nolock) where logtab = '+ char(39)+ @tab + char(39) + ' and logReg.value(' + char(39) set @sel = @sel +'(//@' + @filter + ')[1]' + char(39) + ', ' + char(39) + @filterTip + char(39) + ') IN (SELECT Id FROM @RefValue)' set @sel = @sel + ' union all ' -- 拼接目标表的查询部分 set @sel = @sel + ' Select 999999999 as logId, '+ char(39)+ @Tab + char(39) +' as logTab, '+ @cmpDat + ' as logDat, ''Actual'' as logHost, ' set @sel = @sel + char(39)+ 'A' + char(39) +' as logOpe, * from ' + @Tab + ' with (nolock)' set @sel = @sel + ' where '+ @filter + ' IN (SELECT Id FROM @RefValue)' set @sel = @sel + ' order by logId;' -- 注意这里要用sp_executesql传递表值参数,不能直接用execute(@sel) EXEC sp_executesql @sel, N'@RefValue dbo.IdList READONLY', @RefValue = @RefValue END GO
3. 调用存储过程的写法
先把多个值插入到表变量里,再传给存储过程:
DECLARE @return_value int DECLARE @RefValues dbo.IdList -- 插入需要查询的多个值 INSERT INTO @RefValues VALUES ('204'), ('205') EXEC @return_value = [dbo].[LOG_ListTab_Key_SP] @Tab = N'CAD_USERS', @RefField = N'usucod', @RefValue = @RefValues SELECT 'Return Value' = @return_value
注意事项
- 方案一的逗号分隔方式简单,但如果你的值本身包含逗号,会导致分割错误,这时候建议用方案二。
- 方案二的表值参数方式更安全,能有效避免SQL注入,是生产环境的推荐方式。
- 记得根据你存储过程里实际的
@filter、@filterTip、@cmpDat变量定义调整代码,确保拼接的SQL语法正确。
备注:内容来源于stack exchange,提问作者Clamarc
相关产品推荐
相关产品推荐

