Probleme – Le bulletin, du détail au classement
Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 21 — Bases de données relationnelles et SQL
Énoncé
On veut produire le bulletin de la classe.
- Le détail : chaque élève, chaque matière, la note et le coefficient — tous les élèves.
- Le récapitulatif : par élève, le nombre de notes, la moyenne simple et la moyenne pondérée, du meilleur au moins bon.
- La même chose, mais en écartant les élèves sans aucune note. Deux écritures.
- Le total de la classe.
Corrigé
1. Le détail, avec deux jointures externes.
SELECT e.nom, m.intitule, n.valeur, m.coef
FROM Eleve e
LEFT JOIN Note n ON n.eleve = e.id
LEFT JOIN Matiere m ON m.code = n.matiere
ORDER BY e.nom, m.intitule;
| nom | intitule | valeur | coef |
|---|---|---|---|
| Alaoui | Informatique | ||
| Alaoui | Mathématiques | ||
| Benali | Informatique | ||
| Benali | Physique | ||
| Cohen | Mathématiques | ||
| Dupont | `NULL` | `NULL` | `NULL` |
La deuxième jointure doit être externe elle aussi, et c'est le point technique. Si l'on écrivait LEFT JOIN Note ... JOIN Matiere ..., la seconde jointure exigerait une correspondance — et la ligne de Dupont, dont n.matiere vaut NULL, n'en aurait aucune : elle serait éliminée, annulant l'effet de la première. Une jointure interne placée après une jointure externe détruit l'externalité, silencieusement.
2. Le récapitulatif.
SELECT e.nom,
COUNT(n.valeur) AS nb,
AVG(n.valeur) AS moyenne,
SUM(n.valeur * m.coef) * 1.0 / SUM(m.coef) AS ponderee
FROM Eleve e
LEFT JOIN Note n ON n.eleve = e.id
LEFT JOIN Matiere m ON m.code = n.matiere
GROUP BY e.id, e.nom
ORDER BY ponderee DESC;
| nom | nb | moyenne | pondérée |
|---|---|---|---|
| Cohen | |||
| Alaoui | |||
| Benali | |||
| Dupont | `NULL` | `NULL` |
Trois détails qui portent chacun une décision :
COUNT(n.valeur)et nonCOUNT(*)— sans quoi Dupont afficherait note (exercice 21.3) ;GROUP BY e.id, e.nomet nonGROUP BY e.nom— deux homonymes seraient fusionnés. On groupe toujours par la clé primaire, et l'on ajoute auGROUP BYles colonnes qu'on veut afficher ;ORDER BY ponderee DESC— l'alias est ici légitime, le tri venant après leSELECT(exercice 21.7). Sur le moteur employé ici, la ligneNULLde Dupont se range en dernier ; la place desNULLdans un tri n'est pas fixée par la norme et diffère d'un moteur à l'autre. Si elle importe, on l'écrit — par exemple en triant d'abord surCOUNT(n.valeur) = 0.
3. Écarter les élèves sans note, deux fois.
-- (a) par le HAVING : on regroupe tout, puis on jette les paquets vides
... GROUP BY e.id, e.nom HAVING COUNT(n.valeur) > 0 ORDER BY ponderee DESC;
-- (b) par la jointure interne : ils ne sont jamais entrés
SELECT e.nom, COUNT(*) AS nb, SUM(n.valeur*m.coef)*1.0/SUM(m.coef) AS ponderee
FROM Eleve e JOIN Note n ON n.eleve = e.id JOIN Matiere m ON m.code = n.matiere
GROUP BY e.id, e.nom ORDER BY ponderee DESC;
Les deux rendent les mêmes trois lignes : Cohen , Alaoui , Benali .
Laquelle préférer ? La (b) est plus rapide — elle ne construit jamais le paquet de Dupont. Mais la (a) est plus honnête : elle dit, dans le texte de la requête, qu'un choix a été fait. La (b) le cache dans le mot JOIN, où personne ne le lira. Sur une requête qu'on relira dans six mois, écrire le choix vaut mieux que l'optimiser.
4. Le total.
SELECT COUNT(*) AS lignes, COUNT(valeur) AS notes,
SUM(valeur) AS somme, AVG(valeur) AS moyenne_globale
FROM Note;
-- 5 | 5 | 66 | 13.2
Ici COUNT(*) et COUNT(valeur) coïncident, puisque Note n'a aucun NULL : c'est la jointure externe, et elle seule, qui en fabriquait. Écrire les deux est un contrôle, pas une redondance — s'ils diffèrent un jour, c'est qu'une valeur manque, et l'on veut le savoir. C'est l'esprit des assertions du chapitre chap:discipline, transposé aux données.
Noter enfin que n'est pas la moyenne des moyennes : celles-ci valent , et , dont la moyenne est . Une moyenne de moyennes n'est pas une moyenne — elle donne le même poids à Cohen, qui a une note, qu'à Alaoui, qui en a deux. La bonne valeur est celle qui divise la somme des notes par leur nombre, ici .
Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.