CodeGym /Cours /SQL SELF /Exemples de requêtes imbriquées complexes : combiner EXIS...

Exemples de requêtes imbriquées complexes : combiner EXISTS, IN, HAVING

SQL SELF
Niveau 14 , Leçon 3
Disponible

Félicitations, on arrive au moment où ça devient vraiment fun ! Aujourd’hui, on va voir comment mélanger différents types de sous-requêtes pour résoudre des problèmes bien velus. EXISTS, IN, HAVING — ce trio magique va te faire sentir comme un vrai magicien des bases de données. On va extraire des données d’une table, les filtrer avec les infos d’une autre, grouper, puis filtrer les groupes. Et en bonus, on va voir quelques astuces pour rendre tes requêtes plus efficaces.

Allez, on commence par poser un problème général qu’on va résoudre petit à petit pendant la leçon.

Énoncé du problème

Imaginons qu’on a une base de données d’université avec trois tables :

Table students

id name group_id
1 Otto 101
2 Maria 101
3 Alex 102
4 Anna 103

Table courses

id name
1 Mathématiques
2 Programmation
3 Philosophie

Table enrollments

student_id course_id grade
1 1 90
1 2 NULL
2 1 85
3 3 70

On doit sélectionner tous les étudiants qui :

  1. Sont inscrits à au moins un cours EXISTS.
  2. N’ont pas de note pour au moins un des cours où ils sont inscrits IN.
  3. Appartiennent à des groupes où la moyenne est supérieure à 80 HAVING.

Solution avec EXISTS et IN

Étape 1 : Vérifier les étudiants inscrits (EXISTS). On commence par la condition la plus simple. On veut savoir quels étudiants sont inscrits à au moins un cours. Pour ça, on peut utiliser EXISTS.

SELECT name
FROM students s
WHERE EXISTS (
  SELECT 1
  FROM enrollments e
  WHERE e.student_id = s.id
);
  1. La requête principale sélectionne les noms depuis la table students.
  2. Dans la sous-requête, on vérifie s’il y a des lignes dans enrollments qui correspondent à l’étudiant du SELECT principal (WHERE e.student_id = s.id).
  3. SELECT 1 sert juste à dire qu’on veut savoir si une ligne existe, pas son contenu.

Résultat :

name
Otto
Maria
Alex

Maintenant, on sait qui est inscrit à des cours. Mais on veut aller plus loin. On veut filtrer ceux qui n’ont pas de note.

Étape 2 : Vérifier l’absence de note (IN + NULL). Maintenant, on ajoute un filtre : on veut seulement les étudiants qui n’ont pas de note pour au moins un cours. Ici, IN et la gestion de NULL vont nous aider.

SELECT name
FROM students s
WHERE id IN (
  SELECT e.student_id
  FROM enrollments e
  WHERE e.grade IS NULL
);
  1. Dans la requête principale, on sélectionne les noms des étudiants.
  2. La sous-requête construit une liste de student_id depuis enrollmentsgrade IS NULL.

Résultat :

name
Otto

Donc, Otto est le seul étudiant qui a un cours sans note. La tension monte ! Mais ce n’est pas fini : il faut prendre en compte seulement les groupes où la moyenne est supérieure à 80.

Solution avec HAVING

Étape 3 : Grouper et filtrer avec HAVING.

Là, il est temps de tout combiner. On doit :

  1. Calculer la moyenne pour chaque groupe.
  2. Filtrer les groupes où la moyenne est supérieure à 80.
  3. Afficher les étudiants de ces groupes, en tenant compte des conditions précédentes.
SELECT name
FROM students s
WHERE s.group_id IN (
  SELECT group_id
  FROM students
  JOIN enrollments ON students.id = enrollments.student_id
  WHERE grade IS NOT NULL
  GROUP BY group_id
  HAVING AVG(grade) > 80
)
AND id IN (
  SELECT e.student_id
  FROM enrollments e
  WHERE e.grade IS NULL
);
  1. La requête principale sélectionne les noms des étudiants qui remplissent toutes les conditions.
  2. La première sous-requête dans le WHERE retourne la liste des group_id pour les groupes avec une moyenne supérieure à 80.
    • On fait un JOIN entre students et enrollments pour récupérer les notes.
    • On ne garde que les lignes où grade IS NOT NULL.
    • On groupe par group_id.
    • On utilise HAVING pour filtrer les groupes.
  3. La deuxième sous-requête dans le WHERE vérifie que l’étudiant a au moins un cours sans note.
  4. Les deux conditions sont combinées avec AND.

Résultat :

name
Otto

Donc, on a vu qu’Otto est non seulement le seul étudiant sans note, mais il est aussi dans un groupe qui cartonne.

Comparer les approches : EXISTS vs IN

EXISTS marche super bien quand tu veux juste vérifier si des lignes existent. C’est efficace, car il s’arrête dès qu’il trouve la première. C’est top pour les grosses tables.

En même temps, IN est utile quand tu veux bosser sur le contenu. Par exemple, si tu veux sortir une liste d’identifiants (id) pour filtrer ensuite. Mais attention, IN peut devenir lent si la sous-requête retourne beaucoup de valeurs.

Quand utiliser HAVING

Pour les données agrégées, quand tu dois filtrer sur le résultat d’un calcul, HAVING est le meilleur choix. Mais si tu peux déplacer la condition dans le WHERE (genre filtrer sur une colonne), ça simplifie la requête et ça va plus vite.

Exemple complet

Pour bien ancrer tout ça, on va voir un autre exemple : sélectionner les groupes où au moins un étudiant a une note inférieure à 75, mais qui ne sont pas inscrits au cours "Philosophie".

Petit rappel de nos tables :

Table students

id name group_id
1 Otto 101
2 Maria 101
3 Alex 102
4 Anna 103

Table courses

id name
1 Mathématiques
2 Programmation
3 Philosophie

Table enrollments

student_id course_id grade
1 1 90
1 2 NULL
2 1 85
3 3 70
SELECT DISTINCT group_id
FROM students s
WHERE group_id IN (
  SELECT s.group_id
  FROM students s
  JOIN enrollments e ON s.id = e.student_id
  WHERE e.grade < 75
)
AND group_id NOT IN (
  SELECT s.group_id                                 -- sous-requête de niveau 1
  FROM students s
  JOIN enrollments e ON s.id = e.student_id
  WHERE e.course_id = (
    SELECT id FROM courses WHERE name = 'Philosophie' -- sous-requête de niveau 2 :P
  )
);
  1. La première sous-requête sélectionne les groupes où il y a au moins un étudiant avec une note inférieure à 75.
  2. La deuxième sous-requête exclut les groupes liés au cours "Philosophie".
  3. On combine les conditions avec IN et NOT IN pour obtenir le résultat final.

Résultat :

group_id
101

À quel point c’est utile ?

Dans la vraie vie, ces techniques te sauvent quand tu dois analyser des relations complexes entre les données. Par exemple :

  • En analytics pour repérer des groupes "spéciaux" de clients (VIP, à problèmes, etc.).
  • En développement de systèmes de recommandation, quand tu filtres les utilisateurs sur plein de critères.
  • En entretien, quand on te demande d’optimiser une requête SQL bien costaud.

Entraîne-toi ! C’est comme ça qu’on devient un boss.

Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION