Możesz to zrobić za pomocą OR
:
WHERE (@Id > 0 AND Table1.Field = @Id)
OR (@Id = 0 AND Table1.Field IN (6,16,18))
Radziłbym jednak użyć (jak powiedziałeś) IF/ELSE
, łącząc ze sobą dwa takie warunki, często można wymusić nieoptymalne plany. Np. W swoim przykładzie możesz uprościć to do schematu w następujący sposób:
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);
To po prostu wypełnia jedną z kolumn liczbami 0-2047 powtórzonymi 4 razy każda (tylko dla niektórych przykładowych danych). Następnie, jeśli utworzę dwie procedury, jedną, która używa „JEŻELI/ELSE”, jedną, która łączy powyższe kryteria:
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
Ponieważ kompilacja zapytań będzie miała miejsce tylko raz (chyba że wyraźnie zaznaczysz inaczej), optymalizator nie wybierze innego planu w zależności od tego, czy do procedury przekażesz 0, czy też przekażesz ID> 0, więc obie z poniższych sytuacji:
EXECUTE dbo.Test 0;
EXECUTE dbo.Test 1;
Daje ten plan:
Druga procedura jest w stanie znacznie lepiej oszacować najlepszy plan wykonania, więc uruchamiając to:
EXECUTE dbo.Test2 0;
EXECUTE dbo.Test2 1;
Daje następujący plan:
Przykłady ze świata rzeczywistego będą oczywiście się różnić i celowo stworzyłem przykład, który potwierdza moją tezę. Duplikowanie dużej ilości kodu wymaga nieco więcej wysiłku przy użyciu IF/ELSE
, ale często warto.