Bạn có thể làm điều đó bằng cách sử dụng OR
:
WHERE (@Id > 0 AND Table1.Field = @Id)
OR (@Id = 0 AND Table1.Field IN (6,16,18))
Tuy nhiên, tôi khuyên bạn nên sử dụng (như bạn đã nói) IF/ELSE
, khi kết hợp hai điều kiện như thế này, bạn thường có thể buộc phải lập kế hoạch dưới mức tối ưu. Ví dụ:Trong ví dụ của bạn, bạn có thể đơn giản hóa điều này thành một lược đồ như sau:
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);
Điều này chỉ đơn giản là điền vào một trong các cột có các số 0-2047 được lặp lại 4 lần mỗi cột (chỉ đối với một số dữ liệu ví dụ). Sau đó, Nếu tôi tạo hai thủ tục, một thủ tục sử dụng 'IF / ELSE', một thủ tục kết hợp các tiêu chí như trên:
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
Vì việc biên dịch các truy vấn sẽ chỉ xảy ra một lần (trừ khi bạn nói rõ ràng khác), trình tối ưu hóa sẽ không chọn một kế hoạch khác tùy thuộc vào việc bạn chuyển 0 hay chuyển ID> 0 cho quy trình, vì vậy cả hai điều sau:
EXECUTE dbo.Test 0;
EXECUTE dbo.Test 1;
Sẽ đưa ra kế hoạch này:
Thủ tục thứ hai có thể ước tính kế hoạch thực thi tốt nhất tốt hơn nhiều, vì vậy hãy chạy nó:
EXECUTE dbo.Test2 0;
EXECUTE dbo.Test2 1;
Đưa ra kế hoạch sau:
Các ví dụ trong thế giới thực rõ ràng sẽ khác nhau, và tôi đã cố tình xây dựng một ví dụ để chứng minh quan điểm của tôi. Sẽ tốn nhiều công sức hơn một chút để sao chép nhiều mã bằng cách sử dụng IF/ELSE
, nhưng nó thường đáng giá.