Oracle
 sql >> Base de données >  >> RDS >> Oracle

Conversion de NOT IN en NOT EXISTS

C'est assez simple, quand on a compris :

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);

Cette ligne compare essentiellement S.S_Id avec tous les e.S_Id valeurs issues de la sous-requête.

Changez maintenant cela en NOT EXISTS et mettre un contrôle d'égalité S.S_Id = e.S_Id , à l'intérieur de la sous-requête :

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);

Le changement mineur possible consiste à réaliser que (SELECT e.S_Id ... n'a pas vraiment besoin du e.S_Id . Sous-requêtes avec EXISTS et NOT EXISTS vérifiez simplement s'il y a des lignes retournées ou non et les valeurs des colonnes n'ont pas d'importance. Vous pouvez mettre SELECT * ou une constante ici (SELECT 1 est courant) ou SELECT NULL ou encore SELECT 1/0 (Oui, ça marchera !) :

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);

Une autre considération majeure est que lorsque vous effectuez la conversion de cette façon, le (apparemment équivalent) NOT EXISTS et NOT IN les écritures d'une requête ne sont réellement équivalentes que si les deux S_Id les colonnes ne sont pas nullables. Si le e.S_Id la colonne est nullable, le NOT IN peut avoir pour résultat que la requête entière ne renvoie aucune ligne (parce que x NOT IN (a, b, c, ...) est équivalent à x<>a AND x<>b AND ... et cette condition ne peut pas être vraie lorsque l'un des a,b,c... est NULL .)

Pour des raisons similaires, vous obtiendrez des résultats différents si le s.S_Id est nullable (ce n'est pas très probable dans ce cas car il s'agit probablement de la clé primaire, mais dans d'autres cas, cela compte.)

Il est donc presque toujours préférable d'utiliser NOT EXISTS , car il se comporte différemment même si l'une ou l'autre des colonnes est nullable (le S.S_Id = e.S_Id check supprimera les lignes avec null plus tôt) et généralement ce comportement est celui recherché. Il y a beaucoup de détails dans la question : PAS DANS vs PAS EXISTE , dans la réponse de @Martin Smith. Vous y trouverez également des moyens de convertir le NOT IN à NOT EXISTS et conservez le comportement lié à null (désagréable).