Anda dapat melakukannya menggunakan OR
:
WHERE (@Id > 0 AND Table1.Field = @Id)
OR (@Id = 0 AND Table1.Field IN (6,16,18))
Namun, saya sarankan menggunakan (seperti yang Anda katakan) IF/ELSE
, saat menggabungkan dua kondisi seperti ini, Anda sering kali dapat memaksakan rencana yang kurang optimal. misalnya Dalam contoh Anda, Anda dapat menyederhanakannya menjadi skema sebagai berikut:
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);
Ini hanya mengisi salah satu kolom dengan angka 0-2047 yang masing-masing diulang 4 kali (hanya untuk beberapa contoh data). Kemudian Jika saya membuat dua prosedur, yang menggunakan 'IF/ELSE' yang menggabungkan kriteria seperti di atas:
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
Karena kompilasi kueri hanya akan terjadi sekali (kecuali jika Anda secara eksplisit mengatakan sebaliknya), pengoptimal tidak akan memilih paket yang berbeda bergantung pada apakah Anda meneruskan 0 atau meneruskan ID> 0 ke prosedur, jadi kedua hal berikut:
EXECUTE dbo.Test 0;
EXECUTE dbo.Test 1;
Akan memberikan rencana ini:
Prosedur kedua dapat memperkirakan rencana eksekusi terbaik dengan lebih baik, jadi jalankan ini:
EXECUTE dbo.Test2 0;
EXECUTE dbo.Test2 1;
Memberikan rencana berikut:
Contoh dunia nyata jelas akan bervariasi, dan saya sengaja membuat contoh yang membuktikan maksud saya. Sedikit lebih banyak upaya untuk menduplikasi banyak kode dengan menggunakan IF/ELSE
, tetapi sering kali sepadan.