在Where子句中有效处理多个可选约束

时间:2009-07-08 21:12:30

标签: sql-server-2005 tsql

这有点像Slow Exists Check的续集。亚历克斯的建议有效,并成功避免了代码重复,但我仍然得到了第二个问题。考虑下面的例子(来自AlexKuznetsov)。在其中,我有两个分支处理1个约束。如果我有2个可选约束,我最终会得到4个分支。基本上,分支数量随着约束的数量呈指数增长。

另一方面,如果我使用多语句表值函数或以其他方式使用临时表,SQL查询优化器无法帮助我,因此事情变得缓慢。我有点不信任动态SQL(我听说它也很慢)。

有人可以提供有关如何在不添加大量if语句的情况下添加更多约束的建议吗?

注意:我以前曾尝试将x is null or inpo = @inpo链接在一起,但这很慢。请记住,虽然inpo = @inpo测试可以通过某种索引黑魔法来处理,但无效测试最终会被评估为表中的每一行。

IF @inpo IS NULL BEGIN
  SELECT a,b,c 
    FROM dbo.ReuseMyQuery(@i1)
    ORDER BY c;
END ELSE BEGIN
  SELECT a,b,c 
    FROM dbo.ReuseMyQuery(@i1)
    WHERE inpo = @inpo
    ORDER BY c;
END

变化二:2个约束:

IF @inpo IS NULL BEGIN      
    IF @inpo2 IS NULL BEGIN
        SELECT a,b,c 
        FROM dbo.ReuseMyQuery(@i1)
        ORDER BY c;
    END ELSE BEGIN
        SELECT a,b,c 
        FROM dbo.ReuseMyQuery(@i1)
        WHERE inpo2 = @inpo2
        ORDER BY c;
    END
END ELSE BEGIN
    IF @inpo2 IS NULL BEGIN
        SELECT a,b,c 
        FROM dbo.ReuseMyQuery(@i1)
        WHERE inpo = @inpo
        ORDER BY c;
    END ELSE BEGIN
        SELECT a,b,c 
        FROM dbo.ReuseMyQuery(@i1)
        WHERE inpo = @inpo AND
              inpo2 = @inpo2
        ORDER BY c;
    END
END

5 个答案:

答案 0 :(得分:5)

答案 1 :(得分:1)

在这种情况下,我使用了sp_executesql,如Erland的文章所述:Using sp_executesql 每当使用动态SQL时,缺少权限可能是一个问题,所以我有一个真正的网络帐户进行单元测试,我将该帐户添加到实际角色,并且每当我测试动态SQL时,我都会冒充该真实帐户,如下所述: Database Unit Testing: Impersonation

答案 2 :(得分:0)

Select blah from foo    
Where (@inpo1 is null or @inpo1 = inpo1)
and (@inpo2 is null or @inpo2 = inpo2)

显然这太慢了。有趣。

您是否考虑过代码生成?如果必须直接维护,那么冗长的查询只会出现重复问题。

答案 3 :(得分:0)

这是一个粗略的例子。修改WHERE子句中的LIKE语句,具体取决于您是否要在查询中使用“starts with”或“contains”或完全匹配。

CREATE PROCEDURE dbo.test
@name       AS VARCHAR(50) = NULL,
@address1       AS VARCHAR(50) = NULL,
@address2       AS VARCHAR(50) = NULL,
@city       AS VARCHAR(50) = NULL,
@state      AS VARCHAR(50) = NULL,
@zip_code       AS VARCHAR(50) = NULL
AS

BEGIN

SELECT  [name],
            address1,
            address2,
            city,
            state,
            zip_code
FROM    my_table
WHERE   ([name] LIKE @name + '%' OR @name IS NULL)
            AND (address1 LIKE @address1 + '%' OR @address1 IS NULL)
            AND (address2 LIKE @address2 + '%' OR @address2 IS NULL)
            AND (city LIKE @city + '%' OR @city IS NULL)
            AND (state LIKE @state + '%' OR @state IS NULL)
            AND (zip_code LIKE @zip_code + '%' OR @zip_code IS NULL)
ORDER BY    [name]
END
GO

答案 4 :(得分:0)

我意识到您的问题可能纯粹是学术问题,但如果您有真实世界的用例,您是否考虑过只针对最常见的情况提供优化查询?