sql >> Base de Datos >  >> RDS >> Sqlserver

Declaración de caso Sql dentro de Sql IN

Puedes hacerlo usando un OR :

WHERE   (@Id > 0 AND Table1.Field = @Id)
OR      (@Id = 0 AND Table1.Field IN (6,16,18))

Sin embargo, recomendaría usar (como ha dicho) IF/ELSE , cuando combina dos condiciones como esta, a menudo puede forzar planes subóptimos. por ejemplo, en su ejemplo, podría simplificar esto a un esquema de la siguiente manera:

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);

Esto simplemente llena una de las columnas con los números 0-2047 repetidos 4 veces cada uno (solo para algunos datos de ejemplo). Entonces, si creo dos procedimientos, uno que usa 'IF/ELSE' y otro que combina los criterios anteriores:

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

Dado que la compilación de consultas solo ocurrirá una vez (a menos que usted indique explícitamente lo contrario), el optimizador no elegirá un plan diferente dependiendo de si pasa 0 o pasa una ID> 0 al procedimiento, por lo tanto, ambos de los siguientes:

EXECUTE dbo.Test 0;
EXECUTE dbo.Test 1;

Dará este plan:

El segundo procedimiento es capaz de estimar mucho mejor el mejor plan de ejecución, por lo que ejecuta esto:

EXECUTE dbo.Test2 0;
EXECUTE dbo.Test2 1;

Da el siguiente plan:

Los ejemplos del mundo real obviamente variarán, y he construido deliberadamente un ejemplo que prueba mi punto. Es un poco más difícil duplicar una gran cantidad de código usando IF/ELSE , pero a menudo vale la pena.