参数化的Sql查询

时间:2008-10-03 10:56:55

标签: c# .net sql-server-2005 ado.net

这是我今天破解的坚果

我正在开发的应用程序对SQL有一些高级处理。其中一个操作根据集合中的项目名称从不同的表中选择当前上下文中的对象的各种元数据。为此,执行一系列“select ... from ... where ... in()”,并且为了防止恶意SQL代码,Sql参数用于构造“in()”子句的内容。

但是,当用于构造“in()”子句的项集合大于2100项时,由于每个查询的Sql Server限制了max 2100 Sql参数,因此失败。

我现在尝试的一种方法是创建一个#temp表来存储所有项目名称,然后在原始查询中加入表格,而不是使用“where in()”。这让我对如何使用.NET代码中存储在数组中的项名称填充表格感到头疼。当然,必须有一些批量方式来插入所有内容,而不是为每个项目单独发布“插入”?

除此之外,我对解决这个问题的替代方法非常感兴趣。

非常感谢

7 个答案:

答案 0 :(得分:5)

一种可能的解决方法是使用查询XML的功能,只需将“in”的所有数据作为xml列发送,然后加入即可。

可以使用相同的方法填充临时表,但是为什么不直接使用它。

这是一个简短的样本,应该说明:

declare @wanted xml
set @wanted = '<ids><id>1</id><id>2</id></ids>'
select * 
from (select 1 Id union all select 3) SourceTable 
where Id in(select Id.value('.', 'int') from @wanted.nodes('/ids/id') as Foo(Id))

只需在应用程序中构建xml并将其作为参数传递。

答案 1 :(得分:1)

Hrm,在不知道上下文和更多关于数据以及您如何使用结果和性能问题的情况下,我将尝试建议一种替代方案。你可以分成多个查询吗?像现在一样做,但不是用2100+项目构建查询,而是在每个项目中构建两个1050,然后合并结果。

答案 2 :(得分:1)

预防恶意SQL代码:&gt;使用存储过程。

是的,SQL Server 2005有一个批量插入: http://msdn.microsoft.com/en-us/library/ms188365.aspx

答案 3 :(得分:1)

您可以使用.NET 2.0引入的SqlBulkCopy类。它实际上非常简单易用。看看:

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx

答案 4 :(得分:0)

对于批量更新问题:请查看包含数据表的数据适配器。您可以设置一个参数,允许您批量插入/更新表中的项目,并且您可以选择批次中的项目nr MSDN article

您似乎应该仔细查看业务问题或域,以确定更好的方法来过滤查询中的项目。 IN()子句可能不是您执行此操作的最佳方式。也许在您的情况下,添加数据类别或过滤器而不是要包含的大项目列表会更好。在不了解业务问题/背景的情况下,很难说。

答案 5 :(得分:0)

好的,我不确定这对你有多好或者性能如何,但这里有一些我过去用来实现类似的代码:

    CREATE FUNCTION [dbo].[Split](
    @list ntext
)
RETURNS @tbl TABLE (listpos int IDENTITY(1, 1) NOT NULL,
                          number  int NOT NULL) 
AS
BEGIN
    DECLARE @pos      int,
            @textpos  int,
            @chunklen smallint,
            @str      nvarchar(4000),
            @tmpstr   nvarchar(4000),
            @leftover nvarchar(4000)

    SET @textpos = 1
    SET @leftover = ''
    WHILE @textpos <= datalength(@list) / 2
    BEGIN
       SET @chunklen = 4000 - datalength(@leftover) / 2
       SET @tmpstr = ltrim(@leftover + substring(@list, @textpos, @chunklen))
       SET @textpos = @textpos + @chunklen

       SET @pos = charindex(',', @tmpstr)
       WHILE @pos > 0
       BEGIN
          SET @str = substring(@tmpstr, 1, @pos - 1)
          INSERT @tbl (number) VALUES(convert(int, @str))
          SET @tmpstr = ltrim(substring(@tmpstr, @pos + 1, len(@tmpstr)))
          SET @pos = charindex(',', @tmpstr)
       END

       SET @leftover = @tmpstr
    END

    IF ltrim(rtrim(@leftover)) <> ''
       INSERT @tbl (number) VALUES(convert(int, @leftover))

    RETURN
END

然后在您的其他存储过程中,您可以传入逗号分隔的ID字符串,例如:

select a.number from split('1,2,3') a inner join myothertable b on a.number = b.ID

就像我说的那样,这可能非常糟糕,因为它包含了大量的字符串操作,而且我不记得我从哪里获得了这个功能......但是它可以用来挑选......

我想如果你真的不需要索引原始字符串,你也可以删除填充listpos列的位。

答案 6 :(得分:0)

SQL Server 2008将具有表参数。这是你想要的锤子。