2016-04-01 11 views
1

Ich habe einen SSRS-Bericht, wo es einen Parameter gibt, der den Benutzer auffordert, Datensätze aufzunehmen, bei denen der Umsatz größer als Null ist, oder Datensätze mit Umsatzwerten, die nur Null sind.Wie CASE-Anweisung und einen Parameter in der WHERE-Klausel verwenden?

Da die Abfrage keine gespeicherte Prozedur ist und es keine Option ist, sie in eine Prozedur einzufügen, muss ich einige Falllogik für die eingebettete Abfrage verwenden. Ich muss dies am Ende in der Where-Klausel tun.

Ich versuche, so etwas zu tun:

SELECT * FROM TABLE 
WHERE MY_DATE BETWEEN D_START AND D_END 
AND 
    CASE 
     WHEN :REVENUE = 1 THEN REV != 0 
     WHEN :REVENUE = 2 THEN REV = 0 
    END 

Allerdings, wenn ich diese Abfrage ich folgende Fehlermeldung erhalten, laufen:

ORA-00905: missing keyword 

Ist das, was ich nicht für möglich mache? Oder gibt es einen Fehler, den jemand sehen und mir helfen kann?

Bitte helfen. Vielen Dank!

UPDATE: Um nur zu verdeutlichen, übergibt der Benutzer einen Wert von 1 oder 2. Und die Abfrage sollte die Daten filtern, je nachdem welcher Wert an sie übergeben wird. Wenn im Parameter 1 übergeben wird, filtern Sie alle Einnahmen ungleich Null aus. Sonst, wenn zwei übergeben werden, dann filter, so dass nur Datensätze, bei denen der Umsatz Null ist, zurückgegeben werden.

+1

Es ist * möglich, einen CASE-Ausdruck und einen Parameter in einer WHERE-Klausel zu verwenden. Ich habe ein paar Beispiele angeführt, die dies demonstrieren, zusammen mit einer Erklärung, warum Oracle sich an die Syntax der ursprünglichen Aussage hält. (Die ausgewählte Antwort scheint zu implizieren, dass es nicht möglich ist, einen CASE-Ausdruck in einer WHERE-Klausel zu verwenden.) – spencer7593

+0

@ spencer7593: Es schien wirklich, dass ich CASE für WHERE-Bedingungen ausgeschlossen habe; bearbeitet, danke. Zolt: Um fair zu sein, die akzeptierte Antwort sollte Spencer's sein, was viel besser ist als meiner. – Aleksej

+0

@Aleksej: OP sollte die Antwort wählen, die am besten seinen Bedürfnissen entspricht. Wie Ihre Antwort (richtig) zeigt, benötigt OP in der WHERE-Klausel keinen CASE-Ausdruck. Meine Antwort läuft weit darüber hinaus und gibt eine Erklärung, warum sich Oracle bei der OP-Abfrage verbalgt (eine * Bedingung * zu finden, wo es einen * Wert * erwartet und einen * Wert *, wo es eine * Bedingung * erwartet. (Meine Antwort) wurde auf die allgemeinere Frage im Titel angesprochen ... "Wie man einen CASE-Ausdruck und einen Parameter in einer WHERE-Klausel verwendet." – spencer7593

Antwort

2

Sie können es besser schreiben mit ein bisschen Boolesche Logik:

SELECT * FROM TABLE 
WHERE MY_DATE BETWEEN D_START AND D_END 
AND (
     (:REVENUE = 1 AND REV != 0) 
     OR 
     (:REVENUE = 2 AND REV = 0) 
    ) 

CASE gemeint ist, unterschiedliche Werte auf Bedingungen basieren zu extrahieren, so können Sie es verwenden, um Bedingungen zu überprüfen, aber Sie müssen es benutzen als ein Wert, der auf eine Bedingung überprüft werden soll

+0

Bitte in der Originalfrage nachlesen. – Zolt

+0

@Zolt: Die Antwort sollte schon in Ordnung sein Bearbeiten Sie in der Frage – Aleksej

+0

Awesome.Dies funktioniert.Danke! – Zolt

1

Es ist nicht notwendig, einen Ausdruck CASE zu verwenden, um dieses bestimmte Ergebnis zu erhalten.

Aber es ist möglich, einen zu verwenden.

Das Problem in der ursprünglichen Abfrage ist, dass Oracle strenge als andere Datenbanken (wie MySQL) in dieser Oracle nicht implizit konvertiert einen boolean Ausdruck auf einen Wert oder wandelt einen Wert in ist Boolean.

Ich vermute, dass Oracle an einigen Stellen erstickt. Die Fehlermeldung zeigt uns nur eine davon.

Der CASE-Ausdruck gibt einen Wert und Oracle wird balking, dass er nicht den Wert als boolean auswertet.

Um diesen Wert als Boolean zu erhalten, könnten wir einen Vergleich des Wertes auf einen anderen Wert machen.

Wenn wir das beheben, denke ich, Oracle wird immer noch auf den Ausdruck nach ersticken. Oracle erwartet, einen Wert zurückzugeben, und es findet einen Vergleich, der einen booleschen Wert ergibt.

Okay, wir wissen also, dass der Ausdruck CASE einen Wert zurückgeben muss und wir diesen in einem booleschen Ausdruck verwenden müssen. Wenn wir diesen bedingten Test in den WHEN-Teil verschieben und einen -Wert angeben, der in zurückgegeben werden soll, können wir die Rückgabe des CASE-Ausdrucks mit einem anderen Wert vergleichen.

(Als Nebenbemerkung ... Ich empfehle dringend, dass Sie die Spaltenreferenzen in der SQL-Anweisung zu qualifizieren. Das macht die Absicht deutlicher. Mit Blick auf die Anweisung, MY_DATE, D_START und D_END sind alle Spaltenverweise. das ist völlig in Ordnung, es scheint nur ein bisschen seltsam für mich)

Als Beispiel haben wir so etwas wie dies mit dem CASE Ausdruck tun könnte.

SELECT t.* 
FROM TABLE t 
WHERE t.MY_DATE BETWEEN t.D_START AND t.D_END 
    AND CASE 
     WHEN (:REVENUE = 1 AND t.REV != 0) THEN 1 
     WHEN (:REVENUE = 2 AND t.REV = 0 ) THEN 1 
     ELSE NULL 
     END = 1 

die Pars im Inneren des Gehäuses sind nicht erforderlich; Ich fügte sie nur hinzu, um den Teil hervorzuheben, den Oracle in einem booleschen Kontext bewertet.

Also funktioniert das? Wenn der Wert für: REVENUE 2 ist, wird die Bedingung im ersten WHEN nicht als TRUE ausgewertet (das Ergebnis des ersten Vergleichs ist garantiert FALSE). Die Bedingung im zweiten WHEN kann zu TRUE ausgewertet werden (der erste Vergleich liefert TRUE, das Ergebnis vom zweiten Vergleich hängt vom Wert in der REV Spalte ab).

Dieser CASE-Ausdruck gibt entweder den Wert 1 oder zurück NULL. (Wir könnten genauso gut ein 0 oder ein -1 oder 999 anstelle von NULL verwenden, wenn wir wollen.)

Sobald der CASE-Ausdruck ausgewertet wird, der Wert zurückgegeben wird zu einem wörtlichen Wert verglichen werden, da wenn wir zB schreiben val = 1. Dieser Vergleich wird als boolesch bewertet. Wenn es TRUE ergibt, wird die Zeile zurückgegeben ...

Um Oracle dazu zu bringen, sich ähnlich wie andere Datenbanken (wie MySQL) zu verhalten, müssten wir die Konvertierung von boolesch in Wert und Wert in boolesch explizit machen. Wir würden immer noch die Rückkehr von der CASE im Vergleich zu 1 benötigen, wie wir es oben getan haben. Anstelle von REV != 0 könnten wir einen anderen CASE-Ausdruck verwenden. Ich empfehle dies nicht, nur hier zur Veranschaulichung gezeigt, um eine boolean zu einem Wert konvertieren.

WHERE CASE 
     WHEN (:REVENUE = 1) 
      THEN CASE WHEN (t.REV != 0) THEN 1 ELSE NULL END 
     WHEN (:REVENUE = 2) 
      THEN CASE WHEN (t.REV = 0 ) THEN 1 ELSE NULL END 
     ELSE 
      NULL 
     END = 1 

Beachten Sie, dass die Rückkehr von dem äußersten CASE-Ausdruck wird mit einem Wert verglichen wird, so erhalten wir eine boolean (wo Oracle einen boolean erwartet.)

Alle der ELSE NULL in den Aussagen über seine für ein äquivalentes Ergebnis weggelassen, da, dass der Standard ist, wenn ELSE weggelassen.)


Wieder ist es nicht notwendig, einen CASE Ausdruck zu verwenden. Sie können äquivalente Ergebnisse ohne es erhalten. Zum Beispiel:

SELECT t.* 
    FROM TABLE t 
    WHERE t.MY_DATE BETWEEN t.D_START AND t.D_END 
    AND ( (:REVENUE = 1 AND t.REV != 0) 
     OR (:REVENUE = 2 AND t.REV = 0) 
     ) 

In diesen Abfragen, die alle ein gleichwertiges Ergebnis zurückgeben, wird der CASE Ausdruck kauft uns nichts.Aber unter bestimmten Umständen kann es einige Vorteile gegenüber einem normalen OR haben, weil der Ausdruck CASE die Auswertung stoppt, wenn eine Bedingung in einer WHEN -Klausel zu TRUE auswertet.

0

Das Problem ist, dass Oracle SQL nicht den booleschen Datentyp hat, also können Sie keine Spalten vom Typ boolean haben, boolesche Parameter an eine Abfrage übergeben, boolesche Ausdrücke usw. haben. Sie haben also das etwas unnatürliche Konzept von "condition" das ist etwas, das in logische Bedingungen (wie in der WHERE-Klausel) geht. Leider, als sie den Fall EXPRESSION eingeführt haben, der überall dort verwendet werden kann, wo ein anderer Ausdruck verwendet werden kann (aber das schließt boolean aus), führten sie KEINE "case CONDITION" ein - die verwendet werden könnte, wenn andere Bedingungen verwendet werden können. Diese Auslassung ist seltsam, da der Code für eine Fallbedingung wahrscheinlich 95% des Codes für den Fallausdruck verwenden würde. Umso komischer, da PL/SQL den booleschen Typ hat und der case-Ausdruck dort nahtlos für Booleans funktioniert.

+0

Richtig, Oracle dokumentiert die Datentypen, die von einem CASE-Ausdruck zurückgegeben werden können ... CHAR, VARCHAR2, NUMBER, DATE, et al. Diese Liste der Rückgabetypen schließt "Condition" aus. (In meiner Antwort habe ich wiederholt die Begriffe "boolean" und "comparison" verwendet. Wie Sie richtig betonen, beziehen sich Oracle-Dokumente darauf als "Bedingung". – spencer7593