【问题标题】:Sql Case statement within Sql INSql IN 中的 Sql Case 语句
【发布时间】:2013-09-09 11:19:07
【问题描述】:

我有一个 sql 语句,它的 where 条件如下所示

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)

【问题讨论】:

    标签: sql sql-server-2008 case


    【解决方案1】:

    您可以使用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;
    

    会给出这个计划:

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

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

    给出以下计划:

    现实世界的例子显然会有所不同,我特意构建了一个例子来证明我的观点。使用IF/ELSE 复制大量代码会稍微费力一些,但通常是值得的。

    【讨论】:

    • 太好了,效果很好。在这种情况下,我不能使用if-else,这个主查询已经在运行 inder if-else。所以如果我需要使用if-else,大部分代码都会被复制。
    • 这是一个非常好的例子。我将根据我的情况比较成本计划。谢谢
    【解决方案2】:
    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)
    

    【讨论】:

      猜你喜欢
      • 2014-12-31
      • 2018-10-27
      • 2011-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-16
      • 2013-10-03
      • 1970-01-01
      相关资源
      最近更新 更多