Sql IN中的Sql Case语句

时间:2013-09-09 11:19:08

标签: sql sql-server-2008 case

我有一个sql语句,其条件如下

WHERE (TABLE1.Field=@Id OR (@Id=0))

@Id值为零或更多

时,此方法正常

现在,当@Id值变为0时,我需要匹配多个值。

我尝试过类似下面的东西,但不起作用。我知道我可以在这里使用IF-ELSE,但想知道是否可以使用case statemet

来实现
WHERE TABLE1.Field IN (CASE WHEN @Id>0 THEN @Id ELSE (6,16,18) END)

2 个答案:

答案 0 :(得分:2)

您可以使用OR

来完成
WHERE   (@Id > 0 AND Table1.Field = @Id)
OR      (@Id = 0 AND Table1.Field IN (6,16,18))

但是,我建议使用(正如你所说)IF/ELSE,当将这样的两个条件混合在一起时,你经常可以强制执行不理想的计划。例如,在您的示例中,您可以将其简化为模式,如下所示:

CREATE TABLE T
(   ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY, 
    Field INT NOT NULL, 
    SomeOtherField INT NULL
);
GO
INSERT T  (Field)
SELECT  Number
FROM    Master..spt_values
        CROSS JOIN (VALUES (1), (2), (3)) t (A)
WHERE   Type = 'P'
GO
CREATE NONCLUSTERED INDEX IX_T_Field ON T (Field) INCLUDE (SomeOtherField);

这只是填充其中一列,每个数字0-2047重复4次(仅用于某些示例数据)。然后,如果我创建了两个程序,一个使用“IF / ELSE”程序,它结合了上述标准:

CREATE PROCEDURE dbo.Test @ID INT
AS
    SELECT  ID, Field, SomeOtherField
    FROM    T
    WHERE   (@Id > 0 AND T.Field = @Id)
    OR      (@Id = 0 AND T.Field IN (6,16,18))

GO
CREATE PROCEDURE dbo.Test2 @ID INT
AS
    IF @ID = 0
        SELECT  ID, Field, SomeOtherField
        FROM    T
        WHERE   T.Field IN (6, 16, 18)
    ELSE
        SELECT  ID, Field, SomeOtherField
        FROM    T
        WHERE   T.Field = @Id
GO

由于查询编译只会发生一次(除非您另有明确说明),优化程序将不会选择不同的计划,具体取决于您是传递0还是传递ID> 0到程序,所以以下两个:

EXECUTE dbo.Test 0;
EXECUTE dbo.Test 1;

会给出这个计划:

enter image description here

第二个程序能够更好地估计最佳执行计划,以便运行:

EXECUTE dbo.Test2 0;
EXECUTE dbo.Test2 1;

提供以下计划:

enter image description here

现实世界的例子显然会有所不同,我故意构建了一个证明我的观点的例子。使用IF/ELSE复制大量代码需要付出更多的努力,但这通常是值得的。

答案 1 :(得分:0)

WHERE TABLE1.Field IN (case when @Id>0 THEN @Id else 6 end,
            case when @Id>0 THEN @Id else 16 end,
            case when @Id>0 THEN @Id else 18 end)