存储过程中的条件WHERE子句

时间:2016-06-07 01:02:21

标签: sql sql-server sql-server-2008

这个问题可以归结为更简单的问题,但我仍然很好奇SQL Server / TSQL与条件WHERE条款的接近程度(以及为什么它们不存在的原因也是如此)有趣)。

我有一个存储过程,对于一些参数,它接受一个枚举数组(相应地转换为用户定义的表类型,它基本上模拟了一个int数组)。作为参考,数据类型如下:

CREATE TYPE myIntArray AS TABLE (
    val INT
);

我的存储过程遵循以下几行(更改为更简单化):

CREATE PROCEDURE myProc
    @homeID INT,
    @name VARCHAR(500),
    @hometype_enum myIntArray READONLY,
    @country_enum myIntArray READONLY
AS
BEGIN
    SELECT * FROM my_table
    WHERE name=@name
END
GO

我想要做的是另外根据作为INT表传入的枚举数组的值来过滤查询结果,IFF它们甚至传入了值(表可能是空的) 。伪代码看起来像这样:

SELECT * 
FROM my_table
WHERE name = @name
IF((SELECT COUNT(val) FROM @hometype_enum) > 0)
BEGIN
    AND hometype IN (SELECT val FROM hometype_enum)
END
IF((SELECT COUNT(val) FROM @country_enum ) > 0)
BEGIN
    AND country IN (SELECT val FROM country_enum )
END

这两个枚举是相互独立的,因此可以进行搜索并在没有枚举(两个表都为空),或者两个枚举或两个枚举的情况下进行过滤。

我的实际查询涉及多个列,表和联合(丑陋,我知道),因此它不如能够为每个场景复制/粘贴3行SELECT一样好。我目前正在使用一些非常丑陋的临时表逻辑,我现在不会饶恕读者的眼睛。

除了弄清楚我的特定问题之外,我的主要问题是:SQL Server是否支持条件WHERE子句语句(我确信它不是来自我的研究)?为什么这样(架构,时间复杂,空间复杂性问题)?是否有更多或更少的简洁方法来模拟条件子句,例如taking advantage of conditional short-circuiting

感谢大家的见解。另一天的学习!

2 个答案:

答案 0 :(得分:2)

正如评论中所建议的那样,处理这种条件where子句的最好方法是使用dynamic-sql ......就像....

CREATE PROCEDURE myProc
    @homeID INT,
    @name VARCHAR(500),
    @hometype_enum myIntArray READONLY,
    @country_enum myIntArray READONLY
AS
BEGIN
 SET NOCOUNT ON

 Declare @Sql NVarchar(MAX);

 SET @Sql = N' SELECT * FROM my_table '
          + N' WHERE name = @name '
           + CASE WHEN EXISTS (Select * FROM @hometype_enum)
             THEN N' AND hometype IN (SELECT val FROM hometype_enum) ' ELSE N' ' END
           + CASE WHEN EXISTS (Select * FROM @country_enum)
             THEN N' AND country IN (SELECT val FROM country_enum ) ' ELSE N' ' END

  Exec sp_executesql @Sql
                    ,N'@homeID INT , @name VARCHAR(500),
                      @hometype_enum myIntArray, @country_enum myIntArray'
                    ,@homeID
                    ,@name
                    ,@hometype_enum
                    ,@country_enum

END
GO

使用sp_executesql将允许sql server存储同一存储过程的参数化执行计划。对于相同存储过程的不同组/组合的不同执行计划以获得最佳性能。

答案 1 :(得分:2)

下面的一个也可以。不需要dynamic-sql。 MS SQL可以毫无问题地处理它(具有良好的性能)。

   CREATE PROCEDURE myProc
    @homeID INT,
    @name VARCHAR(500),
    @hometype_enum myIntArray READONLY,
    @country_enum myIntArray READONLY
AS
BEGIN
    SELECT * FROM my_table
    WHERE name=@name
      AND ( ( SELECT count(val)  FROM @hometype_enum ) = 0 
            OR   hometype IN (SELECT val FROM @hometype_enum) )
      AND ( ( SELECT count(val)  FROM @country_enum ) = 0 
            OR   country IN (SELECT val FROM @country_enum) )

END
GO

OR将为您完成工作。当第一部分:SELECT count(val) FROM @hometype_enum ) = 0将返回true时,第二部分将不会被执行 - 空IN子句没有错误。当第一部分将返回一些大于0的值时,将正确评估第二部分。