Bienvenue dans une nouvelle leçon sur SQL ! Aujourd'hui, on va découvrir les opérateurs les plus discrets mais ultra puissants — EXISTS et NOT EXISTS. Imagine un espion qui ne laisse aucune trace, mais qui te dit direct : "Ouais, l'objet existe" ou "Non, c'est vide ici". Ces opérateurs ne renvoient pas de données directement, mais te permettent de faire des vérifications logiques précises dans tes requêtes.
On commence par la base. EXISTS — c'est un opérateur qui vérifie l'existence d'enregistrements dans le résultat d'une sous-requête. Si la sous-requête renvoie au moins une ligne, la condition EXISTS renverra TRUE, sinon — FALSE.
SELECT 1
WHERE EXISTS (
SELECT *
FROM students
WHERE grade > 3.5
);
Comme tu vois, on ne s'intéresse pas aux données de la sous-requête, juste au fait que ces lignes existent. S'il y a au moins un enregistrement qui matche la condition, la requête renvoie 1.
Syntaxe de EXISTS
La syntaxe de EXISTS est super simple :
SELECT colonnes
FROM table
WHERE EXISTS (
SELECT 1
FROM autre_table
WHERE condition
);
Explication :
- La sous-requête à l'intérieur de
EXISTSpeut être n'importe quelle requête. - C'est le résultat de la sous-requête qui décide si on renvoie
TRUEouFALSE.
Exemple : Y a-t-il des étudiants avec une note supérieure à 4 ?
Imaginons la table students :
| id | name | grade |
|---|---|---|
| 1 | Otto | 3.2 |
| 2 | Anna | 4.7 |
| 3 | Dan | 5.0 |
| 4 | Lina | 2.9 |
Disons qu'on veut vérifier s'il existe des étudiants avec une note supérieure à 4. On utilise la requête suivante :
SELECT 'Il y a des étudiants avec une bonne note !'
WHERE EXISTS (
SELECT 1
FROM students
WHERE grade > 4
);
Résultat :
Il y a des étudiants avec une bonne note !
Pourquoi EXISTS est plus rapide que IN ?
Le gros avantage de EXISTS, c'est qu'il arrête la sous-requête dès qu'il trouve une correspondance. Donc si tu veux juste vérifier l'existence de données, EXISTS peut être super efficace.
Par exemple, imagine que la table students contient des millions de lignes, mais tu cherches juste une correspondance (grade > 4). Dès que SQL trouve la première ligne qui matche, la requête s'arrête.
Utilisation de NOT EXISTS
Maintenant, parlons de NOT EXISTS. Cet opérateur fonctionne comme l'opposé de EXISTS. Il renvoie TRUE si la sous-requête ne renvoie aucune ligne.
Exemple : trouver les étudiants sans notes (NULL)
Imaginons que dans notre table, il y a des étudiants qui n'ont pas encore de notes :
| id | name | grade |
|---|---|---|
| 1 | Otto | NULL |
| 2 | Anna | 4.7 |
| 3 | Dan | 5.0 |
| 4 | Lina | NULL |
On veut sélectionner tous les étudiants sans notes. On utilise NOT EXISTS :
SELECT *
FROM students s
WHERE NOT EXISTS (
SELECT 1
FROM students
WHERE grade IS NOT NULL
AND id = s.id
);
Résultat :
| id | name | grade |
|---|---|---|
| 1 | Otto | NULL |
| 4 | Lina | NULL |
Comparaison entre EXISTS et IN
Parfois, on a l'impression que EXISTS et IN font la même chose. À première vue, ouais, mais il y a des subtilités. Surtout si un NULL traîne quelque part. Là, le comportement de IN peut devenir chelou, alors que EXISTS te sauve la mise.
Regardons un exemple.
Table courses (cours qu'on peut suivre) :
| course_id | name |
|---|---|
| 1 | Mathématiques |
| 2 | Histoire |
Et voici les étudiants :
| student_id | name |
|---|---|
| 1 | Alex Lin |
| 2 | Anna Song |
| 3 | Maria Chi |
| 4 | Dan Seth |
| 5 | Shadow Moon |
Table enrollments (qui est inscrit à quel cours) :
| student_id | course_id |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | NULL |
On veut sélectionner les noms des cours où quelqu'un est inscrit. Ça a l'air simple.
Avec IN :
SELECT name
FROM courses
WHERE course_id IN (
SELECT course_id
FROM enrollments
);
À première vue, ça devrait marcher. Mais si dans enrollments il y a un NULL dans courseid, comme pour Maria Chi, IN peut renvoyer... rien du tout ! Parce que NULL rend la sous-requête "indéfinie", et SQL bug : peut-être que NULL c'est justement le courseid qu'on cherche ?
Avec EXISTS :
SELECT name
FROM courses c
WHERE EXISTS (
SELECT 1
FROM enrollments e
WHERE c.course_id = e.course_id
);
Mais EXISTS vérifie juste : "Y a-t-il au moins une ligne où course_id correspond ?" — et c'est tout. Il ne se prend pas la tête avec les NULL, il cherche juste des correspondances précises, pas une liste de valeurs.
Conclusion : si ta sous-requête peut contenir des NULL, mieux vaut utiliser EXISTS pour éviter les surprises.
Exemples de cas réels
Table students :
| id | name |
|---|---|
| 1 | Alex Lin |
| 2 | Anna Song |
| 3 | Maria Chi |
| 4 | Dan Seth |
| 5 | Shadow Moon |
Table enrollments :
| student_id | course_id |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | NULL |
Exemple 1. Étudiants inscrits à des cours
On va trouver ceux qui sont déjà inscrits quelque part — même bizarrement, comme Maria Chi :
SELECT name
FROM students s
WHERE EXISTS (
SELECT 1
FROM enrollments e
WHERE s.id = e.student_id
);
Résultat :
Alex Lin
Anna Song
Maria Chi
Si un étudiant apparaît dans enrollments — il est dans le résultat, même si son course_id est chelou.
Exemple 2. Étudiants sans cours
Maintenant, on cherche ceux qui existent juste dans le système — mais ne sont inscrits nulle part :
SELECT name
FROM students s
WHERE NOT EXISTS (
SELECT 1
FROM enrollments e
WHERE s.id = e.student_id
);
Résultat :
Dan Seth
Shadow Moon
On dirait que ces deux-là n'ont pas encore trouvé un cours à leur goût. Ou alors ils ont juste oublié de s'inscrire :)
Exemple 3. Sélectionner les cours avec plus de 5 étudiants inscrits
Table courses :
| course_id | name |
|---|---|
| 1 | Mathématiques |
| 2 | Histoire |
| 3 | Biologie |
| 4 | Philosophie |
Table enrollments :
| student_id | course_id |
|---|---|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
| 6 | 1 |
| 7 | 2 |
| 8 | 2 |
| 9 | 2 |
| 10 | NULL |
On veut trouver les cours où plus de cinq étudiants sont inscrits. Ici, EXISTS demande : "Est-ce qu'il y a au moins un groupe d'inscriptions pour ce cours où il y a plus de cinq étudiants ?"
SELECT name
FROM courses c
WHERE EXISTS (
SELECT 1
FROM enrollments e
WHERE c.course_id = e.course_id
GROUP BY e.course_id
HAVING COUNT(*) > 5
);
Résultat :
Mathématiques
Il n'y a que le cours "Mathématiques" (course_id = 1) qui a six étudiants inscrits. Les autres cours sont moins populaires pour l'instant.
Erreurs fréquentes avec EXISTS et NOT EXISTS
- Mauvaise compréhension de la syntaxe de la sous-requête. Vérifie toujours que ta sous-requête référence bien la table externe.
- Oublier de gérer les
NULL. Même avecEXISTS, parfois tu dois gérer explicitement lesNULL. - Pas d'index sur les champs de la sous-requête. Ça peut vraiment ralentir ta requête.
Voilà, c'est tout pour aujourd'hui ! Maintenant tu sais comment utiliser EXISTS et NOT EXISTS pour vérifier l'existence de données, et aussi la différence avec IN. Dans la prochaine leçon, on continuera à plonger dans les sous-requêtes, en voyant comment les utiliser dans SELECT pour bosser avec des données agrégées.
GO TO FULL VERSION