Du kan göra det med en OR
:
WHERE (@Id > 0 AND Table1.Field = @Id)
OR (@Id = 0 AND Table1.Field IN (6,16,18))
Jag skulle dock råda dig att använda (som du har sagt) IF/ELSE
, när man blandar ihop två tillstånd som detta kan man ofta tvinga fram suboptimala planer. t.ex. i ditt exempel kan du förenkla detta till ett schema enligt följande:
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);
Detta fyller helt enkelt en av kolumnerna med siffrorna 0-2047 upprepade 4 gånger vardera (bara för några exempeldata). Sedan Om jag skapar två procedurer, en som använder 'OM/ELSE' en som kombinerar kriterierna enligt ovan:
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
Eftersom sammanställning av frågor bara sker en gång (om du inte uttryckligen säger något annat), kommer optimeraren inte att välja en annan plan beroende på om du skickar 0 eller skickar ett ID> 0 till proceduren, så båda av följande:
EXECUTE dbo.Test 0;
EXECUTE dbo.Test 1;
Kommer att ge denna plan:
Den andra proceduren kan uppskatta den bästa utförandeplanen mycket bättre så kör den här:
EXECUTE dbo.Test2 0;
EXECUTE dbo.Test2 1;
Ger följande plan:
Exemplen i den verkliga världen kommer uppenbarligen att variera, och jag har medvetet konstruerat ett exempel som bevisar min poäng. Det är lite mer ansträngning att duplicera mycket kod genom att använda IF/ELSE
, men det är ofta värt det.