IN
DSQL, PSQL, ESQL
<value> [NOT] IN (<select_stmt> | <value_list>) <value_list> ::= <value_1> [, <value_2> …]
Das Prädikat IN
prüft, ob der Wert des Ausdrucks auf der linken Seite im Wertesatz der rechten Seite vorkommt.Der Wertesatz darf nicht mehr als 1500 Elemente enthalten.Das IN
-Prädikat kann mit folgender äquivalenter Form ersetzt werden:
(<value> = <value_1> [OR <value> = <value_2> …]) <value> = { ANY | SOME } (<select_stmt>)
Wenn das Prädikat IN
als Suchbedingung in DML-Abfragen verwendet wird, kann der Firebird-Optimizer einen Index auf die Suchspalte nutzen, sofern einer vorhanden ist.
In seiner zweiten Form prüft das Prädikat IN
, ob der linke Ausdruckswert im Ergebnis der Unterabfrage vorhanden ist (oder nicht vorhanden, wenn NOT IN
verwendet wird).
Die Unterabfrage darf nur eine Spalte abfragen, andernfalls wird es zum Fehler “count of column list and variable list do not match” kommen.
Abfragen, die das Prädikat IN
mit einer Unterabfrage verwenden, können durch eine ähnliche Abfrage mittels des EXISTS
-Prädikates ersetzt werden.Zum Beispiel folgende Abfrage:
SELECT
model, speed, hd
FROM PC
WHERE
model IN (SELECT model
FROM product
WHERE maker = 'A');
kann ersetzt werden mittels EXISTS-Prädikat:
SELECT
model, speed, hd
FROM PC
WHERE
EXISTS (SELECT *
FROM product
WHERE maker = 'A'
AND product.model = PC.model);
Jedoch gilt zu beachten, dass eine Abfrage mittels NOT IN
und einer Unterabfrage nicht immer das gleiche Ergebnis zurückliefert wie sein Gegenpart mit NOT EXISTS
.Dies liegt daran, dass EXISTS
immer TRUE oder FALSE zurückgibt, wohingegen IN
NULL
in diesen beiden Fällen zurückliefert:
-
wenn der geprüfte Wert
NULL
ist und dieIN ()
-Liste nicht leer ist -
wenn der geprüfte Wert keinen Treffer in der
IN ()
-Liste enthält und mindestens ein ElementNULL
ist.
Nur in diesen beiden Fällen wird IN ()
NULL
zurückgeben, während das EXISTS
-Prädikat FALSE
zurückgibt ('keine passende Zeile gefunden', engl. 'no matching row found').In einer Suche oder, zum Beispiel in einem IF (…)
-Statement, bedeuten beide Ergebnisse einen “Fehler” und es macht damit keinen Unterschied.
Aber für die gleichen Daten gibt NOT IN ()
NULL
zurück, während NOT EXISTS
TRUE
zurückgibt, was das Gegenteilige Ergebnis ist.
Schauen wir uns das folgendes Beispiel an:
-- Suche nach Bürgern die nicht am gleichen Tag wie eine
-- berühmte New Yorker Persönlichkeit geboren wurden
SELECT P1.name AS NAME
FROM Personnel P1
WHERE P1.birthday NOT IN (SELECT C1.birthday
FROM Celebrities C1
WHERE C1.birthcity = 'New York');
Nehmen wir nun an, dass die Liste der New Yorker Berühmtheiten nicht leer ist und mindestens einen NULL-Geburtstag aufweist.Dann gilt für alle Bürger, die nicht am gleichen Tag mit einer Berühmtheit Geburtstag haben, dass NOT IN
NULL
zurückgibt, da dies genau das ist was IN
tut.Die Suchbedingung wurde nicht erfüllt und die Bürger werden nicht im Ergebnis des SELECT
berücksichtigt, da die Aussage falsch ist.
Bürger, die am gleichen Tag wie eine Berühmtheit Geburtstag feiern, wird NOT IN
korrekterweise FALSE
zurückgeben, womit diese ebenfalls aussortiert werden, und damit keine Zeile zurückgegeben wird.
Wird die Form NOT EXISTS
verwendet:
-- Suche nach Bürgern, die nicht am gleichen Tag wie eine
-- berühmte New Yorker Persönlichkeit geboren wurden
SELECT P1.name AS NAME
FROM Personnel P1
WHERE NOT EXISTS (SELECT *
FROM Celebrities C1
WHERE C1.birthcity = 'New York'
AND C1.birthday = P1.birthday);
nicht-Übereinstimmungen werden im NOT EXISTS
-Ergebnis TRUE
erhalten und ihre Datensätze landen im Rückgabesatz.
Tip
|
Wenn bei der Suche nach einer Nichtübereinstimmung die Möglichkeit besteht, dass |
-
Finde Mitarbeiter mit den Namen “Pete”, “Ann” und “Roger”:
SELECT * FROM EMPLOYEE WHERE FIRST_NAME IN ('Pete', 'Ann', 'Roger');
-
Finde alle Computer, die deren Hersteller mit dem Buchstaben “A” beginnt:
SELECT model, speed, hd FROM PC WHERE model IN (SELECT model FROM product WHERE maker STARTING WITH 'A');