Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Istruzione Sql Case all'interno di Sql IN

Puoi farlo usando un OR :

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

Tuttavia, consiglierei di usare (come hai detto) IF/ELSE , quando si combinano due condizioni come questa, spesso è possibile forzare piani non ottimali. ad esempio, nel tuo esempio potresti semplificarlo in uno schema come segue:

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

Questo compila semplicemente una delle colonne con i numeri 0-2047 ripetuti 4 volte ciascuna (solo per alcuni dati di esempio). Quindi se creo due procedure, una che utilizza 'IF/ELSE' e una che combina i criteri come sopra:

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

Poiché la compilazione delle query avverrà solo una volta (a meno che tu non dica esplicitamente il contrario), l'ottimizzatore non sceglierà un piano diverso a seconda che tu passi 0 o un ID> 0 alla procedura, quindi entrambe le cose seguenti:

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

Darà questo piano:

La seconda procedura è in grado di stimare molto meglio il miglior piano di esecuzione, quindi eseguendo questo:

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

Fornisce il seguente piano:

Gli esempi del mondo reale ovviamente varieranno e ho deliberatamente costruito un esempio che dimostra il mio punto. È leggermente più difficile duplicare molto codice usando IF/ELSE , ma spesso ne vale la pena.