2013-09-09 5 views
1

У меня есть sql заявления, в котором имеет где состояние, как показано нижеSql саз в Sql В

WHERE ([email protected] 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

Вы можете сделать это с помощью 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 или передать идентификатор> 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, но это часто стоит того.

+0

Отлично, это прекрасно работает. Я не могу использовать 'if-else', в этом случае этот основной запрос уже работает inder' if-else'. Поэтому, если мне нужно использовать 'if-else', большая часть кода будет дублироваться. –

+0

Это действительно хороший пример. Я сравню план затрат на основе моего дела. благодаря –

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) 
Смежные вопросы