这是我今天破解的坚果
我正在开发的应用程序对SQL有一些高级处理。其中一个操作根据集合中的项目名称从不同的表中选择当前上下文中的对象的各种元数据。为此,执行一系列“select ... from ... where ... in()”,并且为了防止恶意SQL代码,Sql参数用于构造“in()”子句的内容。
但是,当用于构造“in()”子句的项集合大于2100项时,由于每个查询的Sql Server限制了max 2100 Sql参数,因此失败。
我现在尝试的一种方法是创建一个#temp表来存储所有项目名称,然后在原始查询中加入表格,而不是使用“where in()”。这让我对如何使用.NET代码中存储在数组中的项名称填充表格感到头疼。当然,必须有一些批量方式来插入所有内容,而不是为每个项目单独发布“插入”?
除此之外,我对解决这个问题的替代方法非常感兴趣。
非常感谢
答案 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将具有表参数。这是你想要的锤子。