Es ist ziemlich einfach, wenn Sie den Bogen raus haben:
SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
WHERE s.S_Sex = 'F'
AND S.S_Id NOT IN(SELECT e.S_Id -- take this line
FROM ENROLLMENT e
WHERE e.Mark < 70);
Diese Zeile vergleicht im Wesentlichen S.S_Id
mit allen e.S_Id
Werte, die aus der Unterabfrage stammen.
Ändern Sie das jetzt in NOT EXISTS
und setzen Sie eine Gleichheitsprüfung S.S_Id = e.S_Id
, innerhalb der Unterabfrage:
SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
WHERE s.S_Sex = 'F'
AND NOT EXISTS (SELECT e.S_Id
FROM ENROLLMENT e
WHERE (e.Mark < 70) -- if this is complex, you'll need parentheses
AND S.S_Id = e.S_Id);
Eine geringfügige mögliche Änderung besteht darin, zu erkennen, dass (SELECT e.S_Id ...
benötigt nicht wirklich die e.S_Id
. Unterabfragen mit EXISTS
und NOT EXISTS
Überprüfen Sie einfach, ob Zeilen zurückgegeben werden oder nicht und die Spaltenwerte keine Rolle spielen. Sie können SELECT *
eingeben oder dort eine Konstante (SELECT 1
ist üblich) oder SELECT NULL
oder sogar SELECT 1/0
(Ja, das geht!):
SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
WHERE s.S_Sex = 'F'
AND NOT EXISTS (SELECT 1
FROM ENROLLMENT e
WHERE e.Mark < 70
AND S.S_Id = e.S_Id);
Eine weitere wichtige Überlegung ist, dass, wenn Sie die Konvertierung auf diese Weise durchführen, der (scheinbar äquivalente) NOT EXISTS
und NOT IN
Die Schreibweisen einer Abfrage sind nur dann wirklich gleichwertig, wenn beide S_Id
Spalten sind nicht nullable. Wenn die e.S_Id
Spalte ist nullable, der NOT IN
kann dazu führen, dass die gesamte Abfrage überhaupt keine Zeilen zurückgibt (weil x NOT IN (a, b, c, ...)
entspricht x<>a AND x<>b AND ...
und diese Bedingung kann nicht wahr sein, wenn einer der a,b,c...
ist NULL
.)
Aus ähnlichen Gründen erhalten Sie unterschiedliche Ergebnisse, wenn die s.S_Id
ist nullable (das ist in diesem Fall nicht sehr wahrscheinlich, da es wahrscheinlich der Primärschlüssel ist, aber in anderen Fällen ist es wichtig.)
Daher ist es fast immer besser, NOT EXISTS
zu verwenden , da es sich anders verhält, selbst wenn eine der Spalten nullfähig ist (die S.S_Id = e.S_Id
check verwirft Zeilen mit null früher) und normalerweise ist dieses Verhalten das gewünschte. Die Frage enthält viele Details: NICHT IN vs. NICHT VORHANDEN
, in der Antwort von @Martin Smith. Dort finden Sie auch Möglichkeiten, den NOT IN
umzuwandeln zu NOT EXISTS
und das nullbezogene (unangenehme) Verhalten beibehalten.