带有“IN”语句的sp_executesql

带有“IN”语句的sp_executesql,sql,sql-server-2005,tsql,sp-executesql,Sql,Sql Server 2005,Tsql,Sp Executesql,我试图在SQL 2005中使用sp_executesql来防止SQL注入,我有一个简单的查询,如下所示: SELECT * from table WHERE RegionCode in ('X101', 'B202') 但是,当我使用sp_executesql执行以下命令时,它不会返回任何内容 Set @Cmd = N'SELECT * FROM table WHERE RegionCode in (@P1)' SET @ParamDefinition = N'@P1 varchar(100)

我试图在SQL 2005中使用sp_executesql来防止SQL注入,我有一个简单的查询,如下所示:

SELECT * from table WHERE RegionCode in ('X101', 'B202')
但是,当我使用sp_executesql执行以下命令时,它不会返回任何内容

Set @Cmd = N'SELECT * FROM table WHERE RegionCode in (@P1)'
SET @ParamDefinition = N'@P1 varchar(100)';
DECLARE @Code as nvarchar(100);
SET @Code = 'X101,B202'
EXECUTE sp_executesql @Cmd, @ParamDefinition, @P1 = @Code
以下是我所测试的:

SET @Code = 'X101'   <-- This works, it returns a single region
SET @Code = 'X101,B202'   <--- Returns nothing
SET @Code = '''X101'',''B202'''  <-- Returns nothing

请帮忙。。。。我做错了什么?

它不起作用的原因是@P1被视为一个单一的值

e、 g.当@Code为X101、B202时,查询的运行方式为: 从“X101,B202”中区域编码所在的表中选择* 因此,它正在寻找一个RegionCode,其值包含在@P1中。即使包含单引号,也意味着它在RegionCode中搜索的值应该包含这些单引号

您需要将@Code变量实际连接到@Cmd sql命令文本中,以使其按照您的想法工作:

SET @Code = '''X101'',''B202'''
SET @Cmd = 'SELECT * FROM Table WHERE RegionCode IN (' + @Code + ')'
EXECUTE (@Cmd)
显然,这只会让您面临SQL注入,所以如果您采用这种方法来确保防范这种情况,您需要非常小心

有其他方法可以处理这种情况,即您希望传入要搜索的值的动态列表

请查看上的示例,了解可用于SQL Server 2005的两种方法。其中一个涉及以Value1、Value2、Value3的形式传入CSV列表,然后使用用户定义的函数将其拆分为一个表变量。如果您快速搜索或搜索此站点,会有很多人提到这种方法。拆分后,将该表var加入到主查询中。第二种方法是传入一个包含值的XML blob,并使用SQL Server的内置XML功能。这两种方法都通过该链接中的性能指标进行了演示,它们不需要动态SQL


如果您使用的是SQL Server 2008,那么表值参数将是最佳选择—这是我在该链接中演示的第三种方法,效果最好。

看起来问题在于单个参数。实际上,你最终会得到:

SELECT * from table WHERE RegionCode in ('X101,B202')

也就是说,RegionCode必须等于“X101、B202”或“X101”,“B202”是要工作的完整字符串

最好在此处使用两个参数:

Set @Cmd = N'SELECT * FROM table WHERE RegionCode in (@P1,@P2)'
SET @Code1 = 'X101'
SET @Code2 = 'B202'

但是,如果列表中有两个以上的项,则可能需要使用另一种方法,可能是使用临时表或表值参数。

在SQL Server中有许多方法可以拆分字符串。本文介绍了几乎每种方法的优缺点:

您需要创建一个拆分函数。这就是拆分函数的使用方式:

SELECT
    *
    FROM YourTable                               y
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value
但是在SQLServer中有很多方法可以分割字符串,请参见前面的链接,其中解释了每种方法的优缺点

要使Numbers表方法起作用,您需要执行此一次性表设置,它将创建一个包含1到10000行的表编号:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Numbers
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
设置数字表后,创建此拆分函数:

CREATE FUNCTION [dbo].[FN_ListToTable]
(
     @SplitOn  char(1)      --REQUIRED, the character to split the @List string on
    ,@List     varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN 
(

    ----------------
    --SINGLE QUERY-- --this will not return empty rows
    ----------------
    SELECT
        ListValue
        FROM (SELECT
                  LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue
                  FROM (
                           SELECT @SplitOn + @List + @SplitOn AS List2
                       ) AS dt
                      INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
                  WHERE SUBSTRING(List2, number, 1) = @SplitOn
             ) dt2
        WHERE ListValue IS NOT NULL AND ListValue!=''

);
GO 
这是一个要试用的工作示例,必须先设置数字表和拆分函数:

CREATE TABLE YourTable (PK int primary key, RowValue varchar(5))
INSERT YourTable VALUES (1,'A')
INSERT YourTable VALUES (2,'BB')
INSERT YourTable VALUES (3,'CCC')
INSERT YourTable VALUES (4,'DDDD')
INSERT YourTable VALUES (5,'EEE')
INSERT YourTable VALUES (6,'FF')
INSERT YourTable VALUES (7,'G')

DECLARE @SQL              nvarchar(1000)
       ,@ParamDefinition  nvarchar(1000)
       ,@ParamValue       varchar(100)
SELECT @SQL = N'SELECT * FROM YourTable WHERE PK IN (SELECT ListValue FROM dbo.FN_ListToTable('','',@P1))'
      ,@ParamDefinition = N'@P1 varchar(100)'
      ,@ParamValue = '2,4,,,6,,8,,2,,4'
EXECUTE sp_executesql @SQL, @ParamDefinition, @P1 = @ParamValue
输出:

PK          RowValue
----------- --------
2           BB
4           DDDD
6           FF

(3 row(s) affected)

你解决了这个问题了吗,或者你能为这个问题添加更多的细节吗?
CREATE TABLE YourTable (PK int primary key, RowValue varchar(5))
INSERT YourTable VALUES (1,'A')
INSERT YourTable VALUES (2,'BB')
INSERT YourTable VALUES (3,'CCC')
INSERT YourTable VALUES (4,'DDDD')
INSERT YourTable VALUES (5,'EEE')
INSERT YourTable VALUES (6,'FF')
INSERT YourTable VALUES (7,'G')

DECLARE @SQL              nvarchar(1000)
       ,@ParamDefinition  nvarchar(1000)
       ,@ParamValue       varchar(100)
SELECT @SQL = N'SELECT * FROM YourTable WHERE PK IN (SELECT ListValue FROM dbo.FN_ListToTable('','',@P1))'
      ,@ParamDefinition = N'@P1 varchar(100)'
      ,@ParamValue = '2,4,,,6,,8,,2,,4'
EXECUTE sp_executesql @SQL, @ParamDefinition, @P1 = @ParamValue
PK          RowValue
----------- --------
2           BB
4           DDDD
6           FF

(3 row(s) affected)