sql >> Databasteknik >  >> RDS >> Oracle

Konvertera NOT IN till NOT EXISTS

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.



  1. SQL-'08:Är flera Replace-satser en dålig praxis/finns det ett annat sätt att skriva den här frågan?

  2. Använder Git för att spåra mysql-schema - några frågor

  3. Array i SQL Query?

  4. ALTER TABLE DROP COLUMN misslyckades eftersom ett eller flera objekt har åtkomst till den här kolumnen