在Where子句中选择可能有多个离散值

时间:2013-02-28 22:32:57

标签: sql sql-server

给出像

这样的表格
CREATE TABLE [dbo].[Article](
    [Id] [int] NOT NULL,
    [CategoryId] [int] NOT NULL,
    [Text] [nchar](10) NOT NULL)

允许用户选择他们想要查看数据的一个或多个类别。通常他们会选择1-20个类别。为了适应这种情况,我生成了类似于:

的参数化查询
SELECT * FROM Article
WHERE CategoryId IN (@c1, @c2, @c3, @c4, @c5)

但是,在一些罕见的用例中,用户可以合法地选择数百个类别。这让我发现Linq-to-Entities的局限性,我通过形成ranges of category codes来解决这个问题。不幸的是,这只会推迟问题,因为可以传递给SQL Server的查询大小有限。

我想重构此查询以避免任何硬限制。我的第一个想法是创建一个包含所请求类别的临时表,并对该临时表执行内部联接以代替IN(...)子句。但是,我知道临时表可能很慢。

这个问题是否有更优雅和/或性能更好的解决方案?

2 个答案:

答案 0 :(得分:1)

你的第一直觉是正确的,你可能会发现一个表值变量足以取代临时表。在这样的情况下,不要担心性能;它不会很重要。如果需要,可以始终在临时表上创建索引,但这似乎是不可能的。 CategoryId字段是否有索引?

答案 1 :(得分:1)

编辑:

糟糕。我错过了Linq部分。

这是一个值得一试的替代语法(出于性能原因,不是因为字符串长度原因)

Select * from dbo.Article art where exists ( select null from ( select 0 as MyV union all select 2 as MyV union all select 3 as MyV ) as derived1 where derived1.MyV = art.CategoryId )

......................

这就是我处理它的方式。

有时我的变量表会更改为#temp表。我测试了2种不同的性能方案。

您可以通过xml传递尽可能多的值。

DECLARE @input XML = '<root>
  <category myvalue="1" />
  <category myvalue="2" />
  <category myvalue="3" />
</root>'



declare @holder table ( CatID int )
Insert into @holder (CatID)
SELECT
    myvalue = MyXmlTable.value('(@myvalue)', 'int')
FROM
    @input.nodes('/root/category') AS Tbl(MyXmlTable)


select * from @holder    

SELECT * FROM Article art
where exists (select null from @holder hold where hold.CatID = art.CategoryId

更大写在这里:

http://www.sqlservercentral.com/articles/Stored+Procedures/thezerotonparameterproblem/2283/