Det är ganska enkelt när du får kläm på det:
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);
Den raden jämför i princip S.S_Id
med alla e.S_Id
värden som kommer från underfrågan.
Ändra nu det till NOT EXISTS
och sätt en likhetskontroll S.S_Id = e.S_Id
, inuti underfrågan:
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);
Mindre möjlig ändring är att inse att (SELECT e.S_Id ...
behöver egentligen inte e.S_Id
. Undersökningar med EXISTS
och NOT EXISTS
kolla bara om det finns rader som returneras eller inte och kolumnvärdena spelar ingen roll. Du kan sätta SELECT *
eller en konstant där (SELECT 1
är vanligt) eller SELECT NULL
eller till och med SELECT 1/0
(Ja, det kommer att fungera!):
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);
En annan viktig faktor är att när du gör omvandlingen på detta sätt, (till synes likvärdig) NOT EXISTS
och NOT IN
skrivningar av en fråga är egentligen likvärdiga endast om båda S_Id
kolumner är inte nullbara. Om e.S_Id
kolumnen är nullbar, NOT IN
kan resultera i att hela frågan inte returnerar några rader alls (eftersom x NOT IN (a, b, c, ...)
är ekvivalent med x<>a AND x<>b AND ...
och det villkoret kan inte vara sant när någon av a,b,c...
är NULL
.)
Av liknande skäl kommer du att få andra resultat om s.S_Id
är nullbar (det är inte särskilt troligt i det här fallet eftersom det förmodligen är den primära nyckeln men i andra fall spelar det roll.)
Så det är nästan alltid bättre att använda NOT EXISTS
, eftersom den beter sig annorlunda även om endera kolumnen är nullbar (S.S_Id = e.S_Id
check kommer att kassera rader med null tidigare) och vanligtvis är detta beteende det önskade. Det finns många detaljer i frågan: INTE IN vs INTE FINNS
, i svaret av @Martin Smith. Du hittar också sätt att konvertera NOT IN
till NOT EXISTS
och behålla det nollrelaterade (obehagliga) beteendet.