To dość proste, kiedy to opanujesz:
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);
Ta linia zasadniczo porównuje S.S_Id
ze wszystkimi e.S_Id
wartości, które pochodzą z podzapytania.
Teraz zmień to na NOT EXISTS
i umieść kontrolę równości S.S_Id = e.S_Id
, wewnątrz podzapytania:
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);
Drobną możliwą zmianą jest uświadomienie sobie, że (SELECT e.S_Id ...
tak naprawdę nie potrzebuje e.S_Id
. Podzapytania z EXISTS
i NOT EXISTS
po prostu sprawdź, czy są zwracane wiersze, czy nie, a wartości kolumn nie mają znaczenia. Możesz umieścić SELECT *
lub stała tam (SELECT 1
jest powszechne) lub SELECT NULL
lub nawet SELECT 1/0
(Tak, to zadziała!):
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);
Inną ważną kwestią jest to, że podczas konwersji w ten sposób (pozornie równoważny) NOT EXISTS
i NOT IN
zapisy zapytania są naprawdę równoważne tylko wtedy, gdy oba S_Id
kolumny nie mają wartości null. Jeśli e.S_Id
kolumna jest dopuszczalna, NOT IN
może spowodować, że całe zapytanie nie zwróci żadnych wierszy (ponieważ x NOT IN (a, b, c, ...)
jest odpowiednikiem x<>a AND x<>b AND ...
a warunek ten nie może być spełniony, gdy jeden z a,b,c...
jest NULL
.)
Z podobnych powodów uzyskasz różne wyniki, jeśli s.S_Id
jest wartością null (w tym przypadku jest to mało prawdopodobne, ponieważ jest to prawdopodobnie klucz podstawowy, ale w innych przypadkach ma znaczenie).
Więc prawie zawsze lepiej jest użyć NOT EXISTS
, ponieważ zachowuje się inaczej, nawet jeśli którakolwiek kolumna dopuszcza wartość null (S.S_Id = e.S_Id
check usunie wiersze z wartością null wcześniej) i zwykle to zachowanie jest pożądane. W pytaniu jest wiele szczegółów: NIE W vs NIE ISTNIEJE
, w odpowiedzi @Martin Smith. Znajdziesz tam również sposoby na przekonwertowanie NOT IN
na NOT EXISTS
i zachowaj zerowe (nieprzyjemne) zachowanie.