2014-09-16 15 views
5

Sto provando a scrivere un'istruzione case nella clausola where per una query su cui sto lavorando. Sto importando il codice nei report Crystal e sto essenzialmente cercando di dire se la variabile 'type' è impostata su 'create' run per questo intervallo di date nella clausola where altrimenti eseguita per un intervallo di date differente. Continua a darmi un errore. Non riesco a capire cosa c'è di sbagliato nella mia sintassi qui. Aiuta qualcuno?Istruzione CASE in where clausola nella query tsql

DECLARE @Date1 DATETIME 
DECLARE @Date2 DATETIME 
DECLARE @type VARCHAR(20) 
SET @Date1 = '2010-1-1' 
SET @Date2 = '2010-2-1' 
SET @type = '{?DateType}' 

select * 
from filled 
WHERE 
    (CASE WHEN @type = 'create' THEN 
    filled.CREATEDON >= @Date1 
    AND filled.CREATEDON < DATEADD(d, +1, @Date2) 
    WHEN @type <> 'create' THEN 
    filled.datefilled >= @Date1 
    AND filled.datefilled < DATEADD(d, +1, @Date2) 
    END) 
+0

Che errore ottieni? E perché hai 2 controlli per '@ type = 'create''? – Andrew

+0

Ma allora perché è contrassegnato contro Crystal Report quando è tutto SQL – aMazing

+0

Perché sto importando la query in cristallo. – Barzul

risposta

12

Non hai bisogno di una dichiarazione case

WHERE ((@type = 'create' and filled.CREATEDON >= @Date1 AND filled.CREATEDON < DATEADD(d, +1, @Date2)) or 
     (@type <> 'create' and filled.datefilled >= @Date1 AND filled.datefilled < DATEADD(d, +1, @Date2)) 
    ) 

Questo lascia la logica non chiacchiere si ha nella dichiarazione case. Entrambe le condizioni hanno lo stesso valore per @type. Presumo che sia un refuso.

+0

Sì, era in effetti un errore dovrebbe essere <>. Grazie. – Barzul

7

Usando un'espressione CASE in una clausola WHERE è possibile, ma in generale può essere evitato, e riscritta utilizzando AND/OR, nel tuo caso sarebbe:

WHERE( @Type = 'create' 
    AND filled.CREATEDON >= @Date1 
    AND filled.CREATEDON < DATEADD(d, +1, @Date2) 
    ) 
OR ( @Type != 'create' 
    AND filled.datefilled >= @Date1 
    AND filled.datefilled < DATEADD(d, +1, @Date2) 
    ) 

TUTTAVIA query come questo di solito producono subottimale piani. Si dovrebbe usare IF/ELSE logica, se possibile:

IF @Type = 'create' 
BEGIN 
    SELECT * 
    FROM Filled 
    WHERE Filled.CreatedOn >= @Date1 
    AND  Filled.CreatedOn < DATEADD(DAY, 1, @Date2) 
END 
ELSE 
BEGIN 
    SELECT * 
    FROM Filled 
    WHERE Filled.DateFilled >= @Date1 
    AND  Filled.DateFilled < DATEADD(DAY, 1, @Date2) 
END 

La ragione di questo è il valore di @type non è noto al momento della compilazione, quindi l'ottimizzatore non sa se avrà bisogno per cercare DateFilled o CreatedOn, quindi, non è possibile pianificare l'uso di un indice su entrambe le colonne (se ne esiste una), quindi eseguirà una scansione della tabella indipendentemente dagli indici disponibili. Considerando che se si separa la logica con IF/ELSE non importa quale sia il valore di @type, viene creato un piano per ogni ramo di IF e in ciascun ramo l'ottimizzatore sa quale colonna verrà cercata e può pianificare di utilizzare il indice appropriato.

è anche possibile utilizzare UNION ALL:

SELECT * 
FROM Filled 
WHERE Filled.CreatedOn >= @Date1 
AND  Filled.CreatedOn < DATEADD(DAY, 1, @Date2) 
AND  @Type = 'create' 
UNION ALL 
SELECT * 
FROM Filled 
WHERE Filled.DateFilled >= @Date1 
AND  Filled.DateFilled < DATEADD(DAY, 1, @Date2) 
AND  @Type <> 'create'; 

Anche in questo caso, se esistono indici su DateFilled o CreatedOn questo è molto più in grado di produrre un piano che li usa che usare OR.

Problemi correlati