【问题标题】:Handling the data in an IN clause, with SQL parameters?使用 SQL 参数处理 IN 子句中的数据?
【发布时间】:2008-09-18 14:35:22
【问题描述】:

我们都知道预处理语句是抵御 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 很重要

【问题讨论】:

  • 一个 t-sql 标签也可能是合适的。

标签: vb.net sql-server-2008 tsql sql-injection language-features


【解决方案1】:

给你 - 首先创建以下函数...

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”子句运行额外的“排序”命令。另外 - 在我看来它看起来更好:D!

【讨论】:

  • 这确实解决了解决方案,因为它为您提供了一个很好的功能,可以从您想要的任何分隔值的列表中创建表格 - 为什么要投反对票?
  • 我投票支持你。这也是我们使用的解决方案。与 SQL 2000 一起使用,从概念上讲,初级团队成员很容易掌握。如果可以的话,我会给你5分。我已经在帖子和文章中看到过这种技术。此解决方案也适用于 SQL Report Services。
【解决方案2】:

如果你想传递一个数组,你需要 sql 中的一个函数,该函数可以将该数组变成一个子选择。

这些功能非常常见,大多数自制系统都利用了它们。

大多数商业,或者更专业的 ORM 都是通过做一堆变量来做的,所以如果你有这个工作,我认为这是标准方法。

【讨论】:

    【解决方案3】:

    您可以使用单列 VALUE 创建一个临时表 TempTable 并插入所有 ID。然后你可以用一个子选择来做:

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

    【讨论】:

      【解决方案4】:

      使用 digiguru 发布的解决方案。这是一个很好的可重用解决方案,我们也使用相同的技术。新团队成员喜欢它,因为它可以节省时间并保持我们的存储过程一致。该解决方案也适用于 SQL 报告,因为传递给存储过程以创建记录集的参数在 varchar(8000) 中传递。你只要把它挂起来就可以了。

      【讨论】:

        【解决方案5】:

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

        如果您使用的是 SQL Server 2008,那么您可以研究一下。

        【讨论】:

          【解决方案6】:

          这是我使用的一种技术

          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)
          

          【讨论】:

          • 在生产环境中执行 sql 字符串是一种非常危险的做事方式。
          猜你喜欢
          • 1970-01-01
          • 2010-09-25
          相关资源
          最近更新 更多