CodeGym /Cours /SQL SELF /Utiliser les sous-requêtes dans SELECT

Utiliser les sous-requêtes dans SELECT

SQL SELF
Niveau 14 , Leçon 0
Disponible

J’aimerais revenir encore une fois sur le sujet des sous-requêtes dans SELECT. Surtout sur le fait que la requête interne peut faire référence aux données de la requête externe. Ça a l’air simple, mais en vrai, pas tant que ça. Plongeons encore un peu plus dans ce sujet...

Les sous-requêtes dans SELECT permettent d’ajouter des colonnes supplémentaires avec des valeurs calculées ou des données qui dépendent d’autres enregistrements ou tables. Par exemple, tu peux afficher la liste des étudiants avec leur moyenne, le nombre de cours auxquels ils sont inscrits, ou la note maximale actuelle dans le groupe. C’est super utile quand tu veux analyser les données "à la volée", en créant des colonnes récapitulatives sans prétraitement.

Bases des sous-requêtes dans SELECT

Avant de passer aux exemples, voyons la syntaxe générale. Les sous-requêtes dans SELECT ressemblent à ça :

SELECT column1,
       column2,
       (SELECT agrégation_ou_condition FROM autre_table WHERE condition) AS nouveau_nom_colonne
FROM table_principale;

Fais gaffe, la sous-requête retourne une seule valeur, qui apparaît dans le résultat comme une nouvelle colonne. Et le condition peut faire référence aux colonnes de la table_principale.

Exemple 1 : Ajouter la moyenne d’un étudiant

On commence simple et utile : on a une table students et une table grades où sont stockées les notes des étudiants.

Table students :

id name
1 Alex Lin
2 Anna Song
3 Dan Seth

Table grades :

student_id grade
1 90
1 85
2 76
3 88
3 92

Maintenant, on veut la liste des étudiants avec leur nom et leur moyenne. Pour ça, on utilise une sous-requête dans SELECT :

SELECT
    s.id,
    s.name,
    (SELECT AVG(g.grade) 
     FROM grades g 
     WHERE g.student_id = s.id) AS average_grade
FROM students s;

Résultat :

id name average_grade
1 Alex Lin 87.5
2 Anna Song 76.0
3 Dan Seth 90.0

Ici, la sous-requête (SELECT AVG(g.grade) FROM grades g WHERE g.student_id = s.id) calcule la moyenne pour chaque étudiant. Elle retourne une valeur pour chaque ligne de la table students, et c’est pratique quand t’as pas envie de faire un JOIN ou de préparer des vues à l’avance.

Exemple 2 : Compter le nombre de cours pour chaque étudiant

Maintenant, ajoutons des infos sur les étudiants : combien de cours ils suivent. Pour ça, on a des tables en plus :

Table enrollments :

student_id course_id
1 101
1 102
2 101

On affiche la liste des étudiants avec le nombre de cours auxquels ils sont inscrits :

SELECT
    s.id,
    s.name,
    (SELECT COUNT(*)
     FROM enrollments e
     WHERE e.student_id = s.id) AS course_count -- référence à la table students de la requête externe
FROM students s;

Résultat :

id name course_count
1 Alex Lin 2
2 Anna Song 1
3 Dan Seth 0

La sous-requête (SELECT COUNT(*) FROM enrollments e WHERE e.student_id = s.id) compte le nombre d’enregistrements dans la table enrollments pour chaque étudiant.

Agrégation des données dans les sous-requêtes

Souvent, les sous-requêtes dans SELECT servent à calculer des données agrégées. Des fonctions comme AVG, SUM, COUNT, MAX, MIN permettent de traiter les données directement dans d’autres requêtes.

Exemple 3 : Score total de l’étudiant

Ajoutons le score total pour chaque étudiant. On va utiliser une sous-requête qui fait la somme de toutes les notes de la table grades :

SELECT
    s.id,
    s.name,
    (SELECT SUM(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS total_grade
FROM students s;

Résultat :

id name total_grade
1 Alex Lin 175
2 Anna Song 76
3 Dan Seth 180

Cette sous-requête (SELECT SUM(g.grade) FROM grades g WHERE g.student_id = s.id) additionne les notes de chaque étudiant. Si un étudiant n’a pas de notes, le résultat sera NULL, car SUM retourne NULL s’il n’y a pas de valeurs.

Limites et conseils

  1. Performance. Les sous-requêtes dans SELECT sont exécutées séparément pour chaque ligne de la table principale. Ça peut ralentir grave sur de gros volumes de données. Si tu peux, remplace-les par des JOIN ou utilise des données agrégées préparées à l’avance. Par exemple :
SELECT
    s.id,
    s.name,
    g.total_grade
FROM students s
LEFT JOIN (
    SELECT student_id, SUM(grade) AS total_grade
    FROM grades
    GROUP BY student_id
) g ON s.id = g.student_id;

Cette approche avec JOIN est plus optimale, car le groupement et le calcul se font une seule fois.

2. Problèmes avec NULL.

Si la sous-requête ne trouve pas de données, le résultat sera NULL. Ça peut surprendre. Exemple :

SELECT
    s.id,
    s.name,
    (SELECT SUM(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS total_grade
FROM students s;

Si un étudiant n’a pas d’enregistrements dans grades, le résultat total_grade sera NULL. Pour remplacer NULL par 0, utilise la fonction COALESCE :

SELECT
    s.id,
    s.name,
    COALESCE((SELECT SUM(g.grade)
              FROM grades g
              WHERE g.student_id = s.id), 0) AS total_grade
FROM students s;

Ouais, ici comme premier paramètre de la fonction COALESCE on passe

(
    SELECT SUM(g.grade)
    FROM grades g
    WHERE g.student_id = s.id
)

Optimiser les sous-requêtes dans SELECT

Pour éviter les calculs inutiles et booster les perfs :

  1. Utilise des index sur les colonnes utilisées dans les sous-requêtes. Par exemple, indexer student_id dans la table grades accélère le filtrage.
  2. Remplace les sous-requêtes par des données agrégées préparées avec JOIN si possible.
  3. Limite la quantité de données traitées par les sous-requêtes en filtrant (WHERE).

Exemple final : combiner les sous-requêtes

Récapitulons tout et créons une requête qui affiche le nom de l’étudiant, la moyenne, le nombre de cours et le score total :

SELECT
    s.id,
    s.name,
    (SELECT AVG(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS average_grade,
    (SELECT COUNT(*) 
     FROM enrollments e 
     WHERE e.student_id = s.id) AS course_count,
    (SELECT SUM(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS total_grade
FROM students s;

Cette requête retourne le profil complet de l’étudiant, construit grâce à la puissance des sous-requêtes. On voit la moyenne, le total des notes et le nombre de cours suivis par chaque étudiant. Ce genre de construction est un super moyen d’obtenir rapidement des infos agrégées sans créer de VIEW séparée ou faire des JOIN compliqués.

id name average_grade course_count total_grade
1 Alex Lin 87.5 2 175
2 Anna Song 76.0 1 76
3 Dan Seth 90.0 0 180
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION