如何将包含列表的变量传递给动态SQL查询?

das*_*das 2 sql t-sql sql-server

我有一个函数将一个sting数字列表转换为一个整数表:

USE [IFRS_Temp]
GO
/****** Object:  UserDefinedFunction [dbo].[CSVToTable]    Script Date: 01/12/2019 3:36:10 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER FUNCTION [dbo].[CSVToTable] (@InStr VARCHAR(MAX))
RETURNS @TempTab TABLE
   (id int not null)
AS
BEGIN
    ;-- Ensure input ends with comma
    SET @InStr = REPLACE(@InStr + ',', ',,', ',')
    DECLARE @SP INT
DECLARE @VALUE VARCHAR(1000)
WHILE PATINDEX('%,%', @INSTR ) <> 0 
BEGIN
   SELECT  @SP = PATINDEX('%,%',@INSTR)
   SELECT  @VALUE = LEFT(@INSTR , @SP - 1)
   SELECT  @INSTR = STUFF(@INSTR, 1, @SP, '')
   INSERT INTO @TempTab(id) VALUES (@VALUE)
END
    RETURN
END
Run Code Online (Sandbox Code Playgroud)
declare @listOfIDs varchar(1000);
SET @listOfIDs = '5, 6, 7, 8, 9, 15, 28, 31, 49, 51, 59, 61'; 

select id from  [dbo].[CSVToTable] (@listOfIDs) --this code is ok5
Run Code Online (Sandbox Code Playgroud)

结果是正确的:

6
7
8
9
15
28
31
49
51
59
61
Run Code Online (Sandbox Code Playgroud)

这会引发错误:

exec('select id from  [dbo].[CSVToTable] ('+@listOfIDs+')') -- error
Run Code Online (Sandbox Code Playgroud)

结果:

过程或函数dbo.CSVToTable指定了太多参数.

我需要第二个查询,因为我的查询是动态的.谢谢

Sam*_*ami 6

只是

EXECUTE ('select id from  [dbo].[CSVToTable] ('''+@listOfIDs+''')')
        declare @listOfIDs varchar(1000);
Run Code Online (Sandbox Code Playgroud)

或者,哪种方式更好

SET @listOfIDs = '5, 6, 7, 8, 9, 15, 28, 31, 49, 51, 59, 61'; 

EXECUTE sp_executesql N'select id from  [dbo].[CSVToTable] (@listOfIDs)',
                      N'@listOfIDs VARCHAR(1000)',
                      @listOfIDs;
Run Code Online (Sandbox Code Playgroud)
  • 为什么我会收到此错误?

    过程或函数dbo.CSVToTable指定了太多参数.

因为你真的传递了太多的参数,所以需要更多,以了解这个运行这个查询并看看你真正传递给你的函数

SELECT 'select id from  [dbo].[CSVToTable] ('+@listOfIDs+')';
Run Code Online (Sandbox Code Playgroud)

将返回(这是你真正想要执行的)

select id from  [dbo].[CSVToTable] (5, 6, 7, 8, 9, 15, 28, 31, 49, 51, 59, 61)
Run Code Online (Sandbox Code Playgroud)

而不是(这是你需要的)

SELECT 'select id from  [dbo].[CSVToTable] ('''+@listOfIDs+''')';
Run Code Online (Sandbox Code Playgroud)
  • 好的,但为什么sp_executesql比这更好exec

简单地说,EXEC将强制您将所有变量连接成一个单独的字符串,这是最糟糕的事情,这使得您的代码完全对SQL注入开放.请注意Bad Habits to Kick : Using EXEC() instead of sp_executesql,这并不意味着它sp_executesql是100%安全的,但它允许语句参数化不是EXEC() dos,因此它EXECSQL注入更安全.


最后,因为你标记 并且你没有指定版本,我建议你使用SPLIT_STRING()函数(2016+)rathar而不是你的版本,如果你没有2016+版本,那么创建你自己而不使用WHILE循环来获得更好的性能,导致WHILE循环将执行缓慢,因此你应该避免它.

例子: