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.
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
@ 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
@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