使用SQL参数处理IN子句中的数据?
我们都知道,准备好的语句是抵御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)中传递。我们只需将其连接即可。