使用SQL参数处理IN子句中的数据?

时间:2020-03-06 14:21:38  来源:igfitidea点击:

我们都知道,准备好的语句是抵御SQL注入攻击的最佳方法之一。用" IN"子句创建准备好的语句的最佳方法是什么。有没有简单的方法可以使用未指定数量的值来执行此操作?以以下查询为例。

SELECT ID,Column1,Column2 FROM MyTable WHERE ID IN (1,2,3)

目前,我正在对可能的值进行循环,以构建诸如这样的字符串。

SELECT ID,Column1,Column2 FROM MyTable WHERE ID IN (@IDVAL_1,@IDVAL_2,@IDVAL_3)

是否可以仅使用传递数组作为查询参数的值并按以下方式使用查询?

SELECT ID,Column1,Column2 FROM MyTable WHERE ID IN (@IDArray)

万一重要,我正在VB.Net中使用SQL Server 2000

解决方案

如果要传递数组,则需要sql中的函数,该函数可以将该数组转换为子选择。

这些功能非常常见,大多数自行开发的系统都可以利用它们。

大多数商业的,或者更专业的ORM都是通过做一堆变量来完成工作的,因此,如果我们能正常工作,我认为这是标准方法。

在SQL Server 2008中,他们终于通过添加新的"表"数据类型解决了这一经典问题。显然,这使我们可以传递值的数组,这些值可用于子选择中以完成与IN语句相同的操作。

如果我们使用的是SQL Server 2008,则可以进行研究。

在这里,我们首先创建以下功能...

Create Function [dbo].[SeparateValues]
(
    @data VARCHAR(MAX),
    @delimiter VARCHAR(10) 
) 
    RETURNS @tbldata TABLE(col VARCHAR(10))
As
Begin
    DECLARE @pos INT
    DECLARE @prevpos INT

    SET @pos = 1 
    SET @prevpos = 0

    WHILE @pos > 0 
        BEGIN

        SET @pos = CHARINDEX(@delimiter, @data, @prevpos+1)

        if @pos > 0 
        INSERT INTO @tbldata(col) VALUES(LTRIM(RTRIM(SUBSTRING(@data, @prevpos+1, @pos-@prevpos-1))))

        else

        INSERT INTO @tbldata(col) VALUES(LTRIM(RTRIM(SUBSTRING(@data, @prevpos+1, len(@data)-@prevpos))))

        SET @prevpos = @pos 
    End

    RETURN

END

然后使用以下...

Declare @CommaSeparated varchar(50)
Set @CommaSeparated = '112,112,122'
SELECT ID,Column1,Column2 FROM MyTable WHERE ID IN (select col FROM [SeparateValues](@CommaSeparated, ','))

我认为sql server 2008将允许使用表函数。

更新

我们将使用以下语法来压缩一些额外的性能...

SELECT ID,Column1,Column2 FROM MyTable
Cross Apply [SeparateValues](@CommaSeparated, ',') s
Where MyTable.id = s.col

因为以前的语法使SQL Server使用" IN"子句运行额外的" Sort"命令。另外我认为它看起来更好:D!

这是我使用的一种技术

ALTER   Procedure GetProductsBySearchString
@SearchString varchar(1000),
as
set nocount on
declare @sqlstring varchar(6000)
select @sqlstring = 'set nocount on
select a.productid, count(a.productid) as SumOf, sum(a.relevence) as CountOf 
 from productkeywords a 
 where rtrim(ltrim(a.term)) in (''' + Replace(@SearchString,' ', ''',''') + ''')
 group by a.productid order by SumOf desc, CountOf desc'

exec(@sqlstring)

我们可以使用单个列VALUE创建一个临时表TempTable并插入所有ID。然后,我们可以使用子选择来做到这一点:

SELECT ID,Column1,Column2 FROM MyTable WHERE ID IN (SELECT VALUE FROM TempTable)

使用digiguru发布的解决方案。这是一个很好的可重用解决方案,我们也使用相同的技术。新的团队成员喜欢它,因为它可以节省时间并保持我们的存储过程一致。该解决方案还可以与SQL报表一起很好地使用,因为传递给存储过程以创建记录集的参数在varchar(8000)中传递。我们只需将其连接即可。