2014-09-16 17 views
5

Ich versuche, eine Case-Anweisung in der WHERE-Klausel für eine Abfrage, an der ich arbeite, zu schreiben. Ich importiere den Code in Crystal-Reports-Berichten und ich versuche grundsätzlich zu sagen, ob die Variable 'type' auf 'create' gesetzt ist, laufen Sie für diesen Datumsbereich in der where-Klausel, andernfalls für einen anderen Datumsbereich. Es gibt mir einen Fehler. Ich kann hier nicht erkennen, was mit meiner Syntax falsch ist. Helfen Sie jemandem?CASE-Anweisung in Where-Klausel in Tsql-Abfrage

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

Welchen Fehler bekommen Sie? Und warum hast du 2 Checks für '@ type = 'create''? – Andrew

+0

Aber warum ist gegen Crystal Report markiert, wenn es alle SQL ist – aMazing

+0

Weil ich die Abfrage in Kristall importieren. – Barzul

Antwort

12

Sie brauchen keine case Aussage

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

Dadurch wird die Nicht-sensical Logik lässt Sie in der case Äußerung. Beide Bedingungen haben den gleichen Wert für @type. Ich nehme an, das ist ein Tippfehler.

+0

Ja, es war in der Tat ein Tippfehler, es sollte <> sein. Vielen Dank. – Barzul

7

Mit einem CASE-Ausdruck in einem where-Klausel möglich ist, aber im Allgemeinen kann vermieden werden, und neu geschrieben AND/OR verwenden, es wäre in Ihrem Fall sein:

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

JEDOCH Anfragen wie dies in der Regel nicht optimal produzieren Pläne. Sie sollten IF/ELSE Logik, wenn möglich verwenden:

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 

Der Grund dafür ist der Wert von @type wird bei der Kompilierung nicht bekannt, daher der Optimiser weiß nicht, ob es auf DateFilled oder CreatedOn suchen muß daher Es kann nicht geplant werden, einen Index für eine der beiden Spalten zu verwenden (falls eine vorhanden ist). Daher wird unabhängig von den verfügbaren Indizes ein Tabellenscan durchgeführt. Wenn Sie jedoch die Logik mit IF/ELSE trennen, ist es egal, welcher Wert von @type ist. Für jeden Zweig der IF wird ein Plan erstellt, und in jedem Zweig weiß der Optimierer, welche Spalte gesucht wird und kann die Verwendung planen passender Index.

Sie können auch UNION ALL verwenden:

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

Noch einmal, wenn Indizes existieren auf DateFilled oder CreatedOn dies viel wahrscheinlicher ist, einen Plan zu erzeugen, die sie verwendet als OR verwenden.