您可以使用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 或将 ID > 0 传递给过程来选择不同的计划,因此以下两者:
EXECUTE dbo.Test 0;
EXECUTE dbo.Test 1;
会给出这个计划:
第二个过程能够更好地估计最佳执行计划,所以运行这个:
EXECUTE dbo.Test2 0;
EXECUTE dbo.Test2 1;
给出以下计划:
现实世界的例子显然会有所不同,我特意构建了一个例子来证明我的观点。使用IF/ELSE 复制大量代码会稍微费力一些,但通常是值得的。