Aller au contenu principal

Exercices corrigés : modélisation, algèbre et SQL

Ce que ce chapitre apporte 6 points
  • Construire un MCD puis un MLD à partir d'un énoncé en langage courant.
  • Traduire une association N-M en table de liaison, et placer ses attributs au bon endroit.
  • Écrire les requêtes de création, de modification et d'interrogation, et les faire juger sur plusieurs états de la base.
  • Passer d'une requête SQL à une expression d'algèbre relationnelle, et inversement.
  • Construire un arbre algébrique, en poussant les sélections au plus près des feuilles.
  • Écrire des requêtes imbriquées : sous-requête scalaire, IN, EXISTS, et la négation qui résiste aux NULL.

Le module mis en pratique. Placés après tout le cours, ces trente exercices en reprennent la matière : la modélisation, le SQL, l'algèbre relationnelle et ses arbres, les requêtes imbriquées. Chaque partie nomme le chapitre où elle s'enseigne ; les transactions ont leurs exercices à la fin de leur chapitre.

Les requêtes et les expressions s'écrivent dans la page. « Exécuter » montre ce que la saisie rend ; « Vérifier » la juge sur plusieurs états de la base, ceux que décrit chaque libellé, et sur un cas caché dont seul le verdict s'affiche : il démasque une réponse écrite pour les seules données visibles. Les indices se dévoilent un à un, le dernier nomme le piège de l'exercice, et une correction s'ouvre après deux vérifications ou une réussite. Les modèles, et trois arbres que la machine ne sait pas juger, gardent un corrigé replié, précédé d'un cadre qui fait annoncer ce qu'il doit contenir.

Comment se servir de cette page
  1. Annoncer le résultat avant d'écrire : ses colonnes, son nombre de lignes à peu près.
  2. Écrire, exécuter, comparer à l'annonce, puis vérifier. Un cas qui échoue dit ce qui diffère ; le cas caché dit seulement s'il passe.
  3. En cas de blocage, relire le chapitre de la partie, puis demander un indice, un seul à la fois.
  4. Une fois l'exercice réussi, ouvrir les indices restants : le dernier dit pourquoi la réponse fausse la plus courante semblait raisonnable.

Partie 1, Modélisation, du MCD au MLD

Ces exercices reprennent Du MCD au modèle relationnel. Pour chaque énoncé, identifier d'abord les entités, puis les associations entre elles et leurs cardinalités.

La faute de cette partie est presque toujours la même : ranger dans une entité un attribut qui appartient à l'association, ou traduire une association N-M par une clé étrangère au lieu d'une table. Les cinq corrigés reviennent dessus sous des habillages différents. Un modèle se discute plus qu'il ne se juge : les corrigés restent repliés, et un cadre de calcul fait d'abord compter ce que le MLD doit contenir.

Exercice 1, Bibliothèque

Une bibliothèque gère des livres, des auteurs et des emprunts.

  • Un auteur peut avoir écrit plusieurs livres, et un livre a un seul auteur principal.
  • Un lecteur peut emprunter plusieurs livres, et un livre peut être emprunté par plusieurs lecteurs (à des dates différentes).
  • Pour chaque emprunt, la bibliothèque enregistre la date d'emprunt et la date de retour prévue.
  1. Identifier les entités et leurs attributs.
  2. Identifier les associations et leurs cardinalités.
  3. Proposer un MCD (notation textuelle).
  4. Déduire le MLD correspondant.

Ce que le MLD de la bibliothèque contient

  • 1.

    Combien de tables le MLD de la bibliothèque compte-t-il ?

  • 2.

    Combien de colonnes forment la clé primaire de la table des emprunts ?

  • 3.

    Combien de clés étrangères le MLD déclare-t-il en tout ?

Afficher la correction

Entités et attributs :

  • Auteur : idAuteur, nom, prenom
  • Livre : idLivre, titre, genre, annee
  • Lecteur : idLecteur, nom, prenom, email

Associations :

  • Auteur -(1,N)- Ecrit -(1,1)- Livre → un auteur a écrit au moins un livre, un livre a exactement un auteur principal
  • Lecteur -(0,N)- Emprunt -(0,N)- Livre → association N-M, à laquelle une troisième entité, Date, donne la date d'emprunt ; la date de retour est un attribut de l'association

MCD :

Modèle conceptuel de données
Auteur
idAuteur
nom
prenom
1,N
Ecrit
1,1
Livre
idLivre
titre
genre
annee
0,N
Emprunt
dateRetour
0,N
Lecteur
idLecteur
nom
prenom
email
La troisième patte de la même association : la date fait partie de l'identité de l'emprunt.
Date
dateEmprunt
0,N
Emprunt

Rectangle : entité, identifiant souligné. Losange : association. Les couples min,max portés sur les pattes se lisent depuis l'entité la plus proche.

Une cardinalité décrit l'entité qu'elle touche : le (1,1) collé à Livre dit qu'un livre participe une seule fois à Ecrit, donc qu'il a un seul auteur. C'est ce (1,1), et lui seul, qui décide que la clé étrangère idAuteur se loge dans Livre. Les (0,N) autour d'Emprunt ne se logent nulle part : ils imposent une table, dont la clé réunit celles des trois entités reliées. L'entité Date ne devient pas une table pour autant : elle n'a pas d'autre attribut que sa clé, qui ne sert qu'à entrer dans celle de l'emprunt.

MLD :

Modèle logique de données
Auteur
idAuteur
nom
prenom
Livre
idLivre
titre
genre
annee
idAuteur→ Auteur
Lecteur
idLecteur
nom
prenom
email
Emprunt
idLivre→ Livre
idLecteur→ Lecteur
dateEmprunt
dateRetour

clé primaire clé étrangère, avec la table visée

Le piège : s'arrêter à la clé (idLivre, idLecteur). C'est le réflexe normal, puisque c'est la forme habituelle d'une table de liaison. Mais elle interdit alors qu'un lecteur emprunte deux fois le même livre, ce que l'énoncé autorise expressément en parlant de dates différentes. La date fait partie de l'identité de l'emprunt : elle entre dans la clé primaire. Dans le MCD, cela se dit en reliant l'association à une troisième entité, Date : sa clé rejoint alors les deux autres dans la clé primaire de la table, par la règle ordinaire.

Le contrôle à faire à chaque table de liaison : inventer deux lignes que la réalité autorise, par exemple « le lecteur 3 emprunte le livre 7 en janvier, puis en mars ». Vérifier ensuite que la clé choisie les accepte toutes les deux.

L'exercice La date dans la clé, sur la page Exercices, pose le même problème et le corrige.

Exercice 2, Entreprise et projets

Une entreprise souhaite modéliser ses salariés, départements et projets.

  • Chaque salarié appartient à un seul département.
  • Un salarié peut travailler sur plusieurs projets.
  • Un projet peut impliquer plusieurs salariés.
  • L'entreprise veut aussi connaître le rôle de chaque salarié sur un projet (par exemple développeur, chef de projet).
  1. Proposer le MCD.
  2. Déduire le MLD.
  3. Quelle est la nature de l'association Salarié-Projet ? Comment se traduit-elle en MLD ?

Ce que le MLD de l'entreprise contient

  • 1.

    Combien de tables le MLD compte-t-il ?

  • 2.

    Combien de colonnes compte la table née de l'association entre salariés et projets ?

Afficher la correction

MCD :

Modèle conceptuel de données
Departement
idDept
nomDept
localisation
1,N
Appartient
1,1
Salarie
idSalarie
nom
prenom
0,N
TravailleSur
role
0,N
Projet
idProjet
nomProjet

Rectangle : entité, identifiant souligné. Losange : association. Les couples min,max portés sur les pattes se lisent depuis l'entité la plus proche.

MLD :

Modèle logique de données
Departement
idDept
nomDept
localisation
Salarie
idSalarie
nom
prenom
idDept→ Departement
Projet
idProjet
nomProjet
TravailleSur
idSalarie→ Salarie
idProjet→ Projet
role

clé primaire clé étrangère, avec la table visée

Explication :

  • L'association Département-Salarié est 1-N : elle se traduit par une clé étrangère idDept dans la table Salarie.
  • L'association Salarié-Projet est N-M : elle génère une table de liaison TravailleSur.
  • L'attribut role appartient à l'association (pas à une entité) : il va dans la table de liaison.

Le piège : placer role dans Salarie. L'erreur est naturelle, parce que la phrase de l'énoncé dit « le rôle de chaque salarié » et semble donc décrire le salarié. Le test qui tranche : un même salarié peut-il avoir deux rôles en même temps ? Oui, un par projet. Un attribut qui change selon le projet ne peut pas être rangé dans le salarié.

Exercice 3, Plateforme vidéo

Modéliser une plateforme de vidéos en ligne avec les règles suivantes :

  • Un utilisateur peut poster plusieurs vidéos.
  • Un utilisateur peut commenter plusieurs vidéos.
  • Chaque commentaire est lié à une vidéo et à un utilisateur.
  • Une vidéo peut recevoir plusieurs commentaires.
  • La plateforme veut aussi enregistrer les likes (un utilisateur peut liker plusieurs vidéos).
  1. Proposer le MCD.
  2. Déduire le MLD.

Ce que le MLD de la plateforme contient

  • 1.

    Combien de tables le MLD compte-t-il ?

  • 2.

    Combien de clés étrangères la table des commentaires porte-t-elle ?

  • 3.

    Combien de clés étrangères le MLD déclare-t-il en tout ?

Afficher la correction

MCD :

Modèle conceptuel de données
Les trois liens partant d'Utilisateur, une ligne par lien.
Utilisateur
idUser
nom
email
dateInscription
0,N
Poste
1,1
Video
idVideo
titre
datePublication
duree
Utilisateur
idUser
0,N
Like
dateLike
0,N
Video
idVideo
Utilisateur
idUser
0,N
Ecrit
1,1
Commentaire
idCom
contenu
dateCom
1,1
Porte
0,N
Video
idVideo

Rectangle : entité, identifiant souligné. Losange : association. Les couples min,max portés sur les pattes se lisent depuis l'entité la plus proche.

Utilisateur revient sur les trois lignes, et c'est ce qu'il faut regarder : la même entité y tient trois rôles sans rapport entre eux. Chacun se traduira séparément, et deux d'entre eux seulement donneront une clé étrangère. Le Commentaire porte deux (1,1) : c'est lui qui recevra les deux clés étrangères, vers son auteur et vers sa vidéo.

MLD :

Modèle logique de données
Utilisateur
idUser
nom
email
dateInscription
Video
idVideo
titre
datePublication
duree
idUser→ Utilisateur
Commentaire
idCom
contenu
dateCom
idUser→ Utilisateur
idVideo→ Video
Like
idUser→ Utilisateur
idVideo→ Video
dateLike

clé primaire clé étrangère, avec la table visée

Explication :

  • Video porte la clé idUser car un utilisateur poste une vidéo (association 1-N).
  • Commentaire porte deux clés étrangères : vers l'auteur du commentaire et vers la vidéo concernée.
  • Like est une table de liaison N-M entre Utilisateur et Video.

Le piège : traiter Commentaire et Like de la même façon, puisque les deux relient un utilisateur à une vidéo. Un like n'a pas d'existence propre : deux likes identiques sont le même like, donc une table de liaison suffit. Un commentaire a un contenu, une date, une identité : deux commentaires identiques restent deux commentaires. C'est une entité.

Exercice 4, Hôtel

Un hôtel souhaite gérer ses chambres, ses clients et ses réservations.

  • Un client peut effectuer plusieurs réservations.
  • Une réservation porte sur une seule chambre.
  • Une chambre a un type (simple, double, suite) et un tarif par nuit.
  • L'hôtel enregistre pour chaque réservation la date d'arrivée et la date de départ.
  1. Identifier les entités et leurs attributs.
  2. Identifier les associations et leurs cardinalités.
  3. Proposer le MLD.

Ce que le MLD de l'hôtel contient

  • 1.

    Combien de tables le MLD compte-t-il ?

  • 2.

    Combien de clés étrangères la table des réservations porte-t-elle ?

  • 3.

    Combien de colonnes forment sa clé primaire ?

Afficher la correction

Entités et attributs :

  • Client : idClient, nom, prenom, email, telephone
  • Chambre : idChambre, numero, type, tarifNuit
  • Reservation : idReservation, dateArrivee, dateDepart

Associations :

  • Client -(1,N)- Effectue -(1,1)- Reservation → un client peut avoir plusieurs réservations, une réservation appartient à un seul client
  • Chambre -(0,N)- Concerne -(1,1)- Reservation → une chambre peut être réservée plusieurs fois (à des dates différentes), une réservation porte sur une chambre

MLD :

Modèle logique de données
Client
idClient
nom
prenom
email
telephone
Chambre
idChambre
numero
type
tarifNuit
Reservation
idReservation
dateArrivee
dateDepart
idClient→ Client
idChambre→ Chambre

clé primaire clé étrangère, avec la table visée

Le piège : voir une association N-M entre Client et Chambre et fabriquer une table de liaison Client-Chambre. L'erreur est naturelle, car la forme est la même : deux clés étrangères et des attributs. Ce qui la départage, c'est qu'une réservation s'annule, se modifie, se numérote et se communique au client. Un objet dont l'entreprise parle au quotidien est une entité, pas un lien.

Ce que la clé n'empêche pas : deux réservations de la même chambre sur des dates qui se chevauchent. La clé primaire ne regarde que l'identifiant de la réservation ; ce contrôle-là se fait par une requête avant l'insertion, ou par un déclencheur.

Exercice 5, Réseau social

Un réseau social permet à des utilisateurs de se suivre mutuellement et de publier des posts.

  • Un utilisateur peut suivre plusieurs autres utilisateurs (un abonnement).
  • Un utilisateur peut publier plusieurs posts.
  • Un post peut recevoir des likes d'autres utilisateurs.
  • Le réseau veut savoir qui suit qui et depuis quand.
  1. Identifier les entités et les associations (attention : l'association « suit » est réflexive).
  2. Proposer le MLD.

Ce que le MLD du réseau social contient

  • 1.

    Combien de tables le MLD compte-t-il ?

  • 2.

    Combien de clés étrangères désignent la table des utilisateurs ?

Afficher la correction

Entités :

  • Utilisateur : idUser, pseudo, email, dateInscription
  • Post : idPost, contenu, datePublication

Associations :

  • Suit : Utilisateur -(0,N)- suit -(0,N)- Utilisateur → association réflexive N-M (un utilisateur peut en suivre plusieurs, et être suivi par plusieurs)
  • Publier : Utilisateur -(0,N)- publie -(1,1)- Post → association 1-N
  • Like : Utilisateur -(0,N)- like -(0,N)- Post → association N-M

MLD :

Modèle logique de données
Utilisateur
idUser
pseudo
email
dateInscription
Post
idPost
contenu
datePublication
idUser→ Utilisateur
Abonnement
idSuiveur→ Utilisateur
idSuivi→ Utilisateur
dateAbonnement
LikePost
idUser→ Utilisateur
idPost→ Post

clé primaire clé étrangère, avec la table visée

Point clé, l'association réflexive : la table Abonnement référence deux fois Utilisateur avec deux noms différents (idSuiveur = celui qui suit, idSuivi = celui qui est suivi). Les deux colonnes pointent vers la même table mais ont des rôles distincts. Rien n'empêche encore un utilisateur de se suivre lui-même : une contrainte CHECK (idSuiveur <> idSuivi) l'interdit.

Le piège : nommer les deux colonnes idUser1 et idUser2. Rien ne l'interdit, et au moment où la table est écrite le sens paraît évident. Il ne l'est plus à la première requête : « les abonnés de Marie » et « les comptes que Marie suit » deviennent indiscernables. Dans une association réflexive, le nom de la colonne est la seule trace du rôle.

Partie 2, Créer, modifier et interroger en SQL

La modélisation étant faite, la suite l'exécute : les mêmes entités deviennent des tables, puis des résultats. Ces exercices reprennent Les requêtes SQL et, pour les comptes et les moyennes des exercices 8 et 9, le début de SQL avancé.

Chaque vérification part de la base du module, celle des chapitres sur l'algèbre et sur le SQL, puis la modifie comme le dit son libellé : un étudiant de plus, une note changée, un cours qui ouvre. Le bouton du schéma, en tête de l'éditeur, en montre les tables. Quand l'énoncé demande un ordre, l'ordre des lignes compte ; sinon, il est libre.

Schéma de référence :

Modèle logique de données
Etudiant
idEtudiant
nom
prenom
dateNaissance
email
ville
idClasse→ Classe
actif
Cours
idCours
intitule
volumeHoraire
coefficient
idEnseignant→ Enseignant
Inscription
idEtudiant→ Etudiant
idCours→ Cours
note

clé primaire clé étrangère, avec la table visée

Ce que la base contient : dix étudiants, sept cours, vingt-cinq inscriptions dont deux sans note. Une requête sur les inscriptions qui rend plus de vingt-cinq lignes a dupliqué quelque chose ; une requête qui en rend moins a filtré quelque chose, volontairement ou non.

Exercice 6, Mise en place du schéma

Créer, dans une base vide, une version réduite du schéma, puis la remplir. Trois tables :

  • Etudiant : idEtudiant, clé primaire ; nom et prenom, obligatoires ; dateNaissance.
  • Cours : idCours, clé primaire ; intitule, obligatoire ; volumeHoraire.
  • Inscription : idEtudiant, idCours et note. La clé primaire est le couple. Supprimer un étudiant supprime ses inscriptions ; supprimer un cours qui a des inscrits est refusé.

Les données à insérer :

idEtudiantnomprenomdateNaissance
1DurandClaire2001-03-25
2MartinLucas2000-07-14
3LefevreSophie2002-11-02
4BernardTom2001-09-10
idCoursintitulevolumeHoraire
1Mathematiques30
2Physique24
3Informatique36
idEtudiantidCoursnote
1114.5
1316
2111
229.5
3213
4312
Exercice : écrire puis vérifier

Trois tables, leurs clés, et leurs données

Écrire le script qui crée les trois tables et y insère les données des trois tableaux. Les identifiants sont des INTEGER PRIMARY KEY, la note un REAL, les autres colonnes des TEXT ou des INTEGER ; les colonnes que l'énoncé ne dit pas obligatoires ne le sont pas.

La vérification lit les clés primaires des trois tables, les colonnes obligatoires, les clés étrangères d'Inscription avec ce qu'elles font d'une suppression, puis chaque inscription avec le nom de l'étudiant et l'intitulé du cours. Un SELECT ajouté en fin de script, pour voir le résultat, ne gêne pas la vérification.

« Exécuter » joue le script et montre l'état de la base qu'il laisse ; « Vérifier » compare cet état à celui attendu, sur 1 cas.

Sous MySQL, l'identifiant s'écrirait INT PRIMARY KEY AUTO_INCREMENT, le nom VARCHAR(50) et la note DECIMAL(4,2). La page exécute SQLite, où INTEGER PRIMARY KEY s'incrémente seul ; elle signale un AUTO_INCREMENT au lieu de l'exécuter.

Exercice 7, Filtrage sur les notes

Exercice : écrire puis vérifier

Les inscriptions notées au moins 12

Écrire une requête qui renvoie le nom, le prénom et la note de chaque inscription notée au moins 12, de la meilleure note à la moins bonne.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Exercice 8, Comptage par cours

Exercice : écrire puis vérifier

Le nombre d'inscrits de chaque cours

Écrire une requête qui renvoie l'intitulé de chaque cours et son nombre d'inscrits, du cours le plus suivi au moins suivi et, à nombre égal, par ordre alphabétique des intitulés.

Un cours qui n'a aucun inscrit figure dans le résultat, avec 0. Le départ est un premier jet, à essayer avant de le corriger.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Le second critère du ORDER BY départage les ex æquo : sans lui, deux cours à cinq inscrits sortent dans un ordre que rien ne fixe, et qui change d'un moteur à l'autre.

Exercice 9, Agrégats et filtrage de groupes

Exercice : écrire puis vérifier

Les cours suivis et bien notés

Écrire une requête qui renvoie l'intitulé, le nombre d'inscrits et la moyenne des notes, arrondie à deux décimales par ROUND(..., 2), de chaque cours qui a au moins deux inscrits et une moyenne strictement supérieure à 11, de la meilleure moyenne à la moins bonne.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Sur la base du cours, Reseaux a deux inscrits mais 10.75 de moyenne : les deux conditions ne font pas double emploi, et la deuxième vérification montre un cours écarté par chacune. L'exercice Filtrer les groupes, sur la page Exercices, revient sur le partage entre WHERE et HAVING.

Exercice 10, Ce qui n'existe pas

Une question en « aucun » ne se répond pas en filtrant : les lignes cherchées sont précisément celles qui manquent. La requête doit construire l'absence.

Exercice : écrire puis vérifier

Les cours sans étudiant parisien

Écrire une requête qui renvoie l'intitulé de chaque cours auquel aucun étudiant habitant Paris n'est inscrit.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Si la sous-requête rendait une seule valeur NULL, NOT IN ne rendrait plus aucune ligne, sans le moindre message. Ici la clé primaire interdit qu'idCours soit nulle, sous MySQL comme dans la page ; l'exercice 30 montre une colonne qui, elle, contient des NULL. Sans le filtre sur la ville, la requête cherche les cours sans aucun inscrit, et ne rend rien sur la base du cours : un résultat vide est une réponse, pas une panne. L'exercice Aucun inscrit de Paris, sur la page Exercices, pose la même question en variant les données.

Exercice 11, UPDATE et DELETE

Sur la base du module, dont la table Inscription déclare ON DELETE CASCADE vers Etudiant :

  1. L'étudiante Sophie Dupond, d'identifiant 3, a changé de nom : elle s'appelle désormais Dupont. Mettre à jour la table.
  2. L'étudiant Tom Durand, d'identifiant 4, quitte l'école. Le supprimer ainsi que toutes ses inscriptions.
  3. À quelle condition ses inscriptions disparaîtront-elles sans être supprimées une par une ?
Exercice : écrire puis vérifier

Renommer, puis supprimer avec les inscriptions

Écrire le script qui renomme Sophie Dupond (identifiant 3) en Dupont, puis supprime Tom Durand (identifiant 4) avec toutes ses inscriptions.

La vérification lit, après le script, chaque étudiant (identifiant, nom, prénom) et chaque inscription. Certaines vérifications ajoutent d'abord un homonyme.

« Exécuter » joue le script et montre l'état de la base qu'il laisse ; « Vérifier » compare cet état à celui attendu, sur 3 cas, dont 1 caché.

La question 3 tient au moteur : une contrainte écrite dans le CREATE TABLE n'agit que s'il la vérifie. MySQL vérifie toujours les clés étrangères de ses tables InnoDB, et la page les a activées pour faire comme lui. Le bloc suivant supprime Sofia Petit, qui a une seule inscription, puis compte les inscriptions restantes.

requete.sql
Résultat
>_ Prêt à exécuter…
À manipuler
Ajouter PRAGMA foreign_keys = OFF; en tête du bloc et relancer : le compte passe de 24 à 25. Sofia Petit a disparu, son inscription est restée, et rien ne le signale : la base contient une inscription qui désigne un étudiant inexistant. Cette ligne est propre à SQLite, que MySQL refuserait ; son équivalent sous MySQL s'écrit SET FOREIGN_KEY_CHECKS = 0.

L'exercice Renommer et retirer, sur la clé, sur la page Exercices, refait ce geste sur deux autres étudiants.

Exercice 12, ALTER TABLE

Sur la base du module :

  1. Ajouter une colonne mention de type VARCHAR(20) à la table Inscription, avec la valeur par défaut 'Passable'.
  2. Ajouter une contrainte UNIQUE sur la colonne email de la table Etudiant.
  3. Supprimer la colonne dateNaissance de la table Etudiant.

La base du module déclare déjà email unique : la question 2 suppose une table qui ne l'est pas encore, et se traite après le bloc, qui vérifie les deux autres.

Exercice : écrire puis vérifier

Une colonne de plus, une colonne de moins

Écrire le script qui ajoute à Inscription la colonne mention, de type VARCHAR(20) et de valeur par défaut 'Passable', puis supprime la colonne dateNaissance d'Etudiant.

La vérification lit les colonnes des deux tables, la valeur par défaut de chaque colonne d'Inscription, et la mention de chaque inscription.

« Exécuter » joue le script et montre l'état de la base qu'il laisse ; « Vérifier » compare cet état à celui attendu, sur 3 cas, dont 1 caché.

La question 2. Sous MySQL, une contrainte s'ajoute par ALTER TABLE et se nomme, pour pouvoir la retirer plus tard par DROP CONSTRAINT uq_email :

SQL
ALTER TABLE Etudiant
ADD CONSTRAINT uq_email UNIQUE (email);

SQLite, le moteur de la page, ne sait pas ajouter de contrainte à une table existante : il écrit la même règle par un index unique, CREATE UNIQUE INDEX uq_email ON Etudiant(email), que MySQL accepte aussi. Dans les deux écritures, le moteur contrôle d'abord l'existant, et refuse la contrainte si deux lignes se répètent déjà : une contrainte ne se déclare jamais sans avoir cherché les doublons qu'elle va interdire. Plusieurs NULL ne se comptent pas comme des doublons, et les deux étudiants de la base sans email passent.

Exercice 13, LIKE, BETWEEN et IS NULL

Trois requêtes sur le schéma de référence : les noms qui commencent par une lettre, un intervalle de volumes horaires, les notes non saisies.

Exercice : écrire puis vérifier

Les noms qui commencent par D ou par M

Écrire une requête qui renvoie le nom et le prénom de chaque étudiant dont le nom commence par « D » ou par « M ».

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Exercice : écrire puis vérifier

Les cours de 25 à 40 heures

Écrire une requête qui renvoie l'intitulé et le volume horaire de chaque cours de 25 à 40 heures, bornes comprises.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Exercice : écrire puis vérifier

Les inscriptions sans note

Écrire une requête qui renvoie l'identifiant de l'étudiant et celui du cours de chaque inscription dont la note n'est pas encore saisie.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Les exercices L'email absent et Bornes incluses, sur la page Exercices, reprennent les deux derniers pièges.

Vérification rapideon peut se reprendre

1.Un énoncé dit qu'un étudiant suit plusieurs cours et qu'un cours accueille plusieurs étudiants. Que produit le MLD ?

2.La table Inscription déclare ON DELETE CASCADE vers Etudiant. Quand la suppression d'un étudiant emporte-t-elle ses inscriptions ?

Partie 3, Algèbre relationnelle

Exprimer les requêtes suivantes en utilisant les opérateurs σ (sélection), π (projection), ⨝ (jointure), ∪ (union), − (différence), ÷ (division).

Ces exercices reprennent L'algèbre relationnelle et ses arbres. SQL dit ce qu'on veut, l'algèbre dit dans quel ordre l'obtenir, ce que la partie 4 dessinera ensuite.

Les symboles s'écrivent avec la barre placée au-dessus de la zone de saisie ; au clavier, et, ou, non, <=, >= et le tiret conviennent aussi. Une table écrite dans un cas prend la place de la table du cours de même nom, les autres restent. À chaque vérification, l'arbre de l'expression se dessine, et chaque nœud se clique.

Exercice 14, Projection + sélection

Exercice : écrire puis vérifier

Les inscrits en mathématiques

Écrire l'expression qui donne le nom et le prénom de chaque étudiant inscrit au cours dont l'intitulé est Mathematiques.

Expression à écrire

Une condition ou une liste d'attributs s'écrit en indice, entre accolades, une chaîne entre apostrophes, un nombre décimal avec un point. Au clavier, et, ou, non, <>, <=, >= et le tiret de la différence conviennent aussi.

Écrire l'expression, puis « Vérifier » : elle est calculée sur 3 cas, dont 1 caché, et comparée à la correction calculée sur les mêmes tables.

Les tables du cas « trois inscriptions seulement »
Inscription
idEtudiantidCoursnote
1317
439
5412

Les autres tables sont celles du cours.

L'exercice Sélection puis projection, sur la page Exercices, revient sur cet ordre.

Exercice 15, Sélection sur une table liée

Exercice : écrire puis vérifier

Les cours de Tom Durand

Écrire l'expression qui donne l'intitulé de chaque cours que suit l'étudiant Tom Durand, dont l'identifiant est 4.

Expression à écrire

Une condition ou une liste d'attributs s'écrit en indice, entre accolades, une chaîne entre apostrophes, un nombre décimal avec un point. Au clavier, et, ou, non, <>, <=, >= et le tiret de la différence conviennent aussi.

Écrire l'expression, puis « Vérifier » : elle est calculée sur 3 cas, dont 1 caché, et comparée à la correction calculée sur les mêmes tables.

Les tables du cas « un second Tom Durand s'est inscrit »
Etudiant
idEtudiantnomprenomdateNaissanceemailvilleidClasseactif
4DurandTom2003-05-30tom.durand@ecole.frNantes20
11DurandTom2005-02-11NULLLyon11
Inscription
idEtudiantidCoursnote
42NULL
447
11612

Les autres tables sont celles du cours.

Exercice 16, Sélection avec condition numérique

Exercice : écrire puis vérifier

Les étudiants qui ont une note sous 10

Écrire l'expression qui donne le nom et le prénom de chaque étudiant qui a obtenu au moins une note strictement inférieure à 10.

Expression à écrire

Une condition ou une liste d'attributs s'écrit en indice, entre accolades, une chaîne entre apostrophes, un nombre décimal avec un point. Au clavier, et, ou, non, <>, <=, >= et le tiret de la différence conviennent aussi.

Écrire l'expression, puis « Vérifier » : elle est calculée sur 3 cas, dont 1 caché, et comparée à la correction calculée sur les mêmes tables.

Les tables du cas « une note de 10 tout juste, et deux notes sous 10 pour le même étudiant »
Inscription
idEtudiantidCoursnote
1310
218.5
239
5112

Les autres tables sont celles du cours.

Exercice 17, Division relationnelle

Exercice : écrire puis vérifier

Les étudiants inscrits à tous les cours

Écrire l'expression qui donne le nom et le prénom de chaque étudiant inscrit à tous les cours de la table Cours.

Expression à écrire

Une condition ou une liste d'attributs s'écrit en indice, entre accolades, une chaîne entre apostrophes, un nombre décimal avec un point. Au clavier, et, ou, non, <>, <=, >= et le tiret de la différence conviennent aussi.

Écrire l'expression, puis « Vérifier » : elle est calculée sur 3 cas, dont 1 caché, et comparée à la correction calculée sur les mêmes tables.

Les tables du cas « deux cours seulement, Bases de donnees et Mathematiques »
Cours
idCoursintitulevolumeHorairecoefficientidEnseignant
1Bases de donnees3021
3Mathematiques362.53

Les autres tables sont celles du cours.

L'exercice 27 écrit la même division en SQL. L'exercice Division par tous, sur la page Exercices, en pose une autre.

Exercice 18, Union

Exercice : écrire puis vérifier

Les inscrits en mathématiques ou en physique

Écrire l'expression qui donne l'identifiant (idEtudiant) de chaque étudiant inscrit au cours Mathematiques, au cours Physique, ou aux deux.

Expression à écrire

Une condition ou une liste d'attributs s'écrit en indice, entre accolades, une chaîne entre apostrophes, un nombre décimal avec un point. Au clavier, et, ou, non, <>, <=, >= et le tiret de la différence conviennent aussi.

Écrire l'expression, puis « Vérifier » : elle est calculée sur 3 cas, dont 1 caché, et comparée à la correction calculée sur les mêmes tables.

Les tables du cas « quatre inscriptions seulement »
Inscription
idEtudiantidCoursnote
1317
2314
3412
5118

Les autres tables sont celles du cours.

L'union est ensembliste : un étudiant inscrit aux deux cours n'y figure qu'une fois. SQL la traduit par UNION, qui empile deux SELECT rendant les mêmes colonnes et retire les doublons.

Exercice : écrire puis vérifier

La même union, en SQL

Écrire en SQL la requête de l'exercice : l'identifiant de chaque étudiant inscrit au cours Mathematiques, au cours Physique, ou aux deux, chacun une seule fois. Les cours se désignent par leur intitulé.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

L'étape suivante fait le compte de l'union de travers, à trouver.

Une union comptée trop vite

Une seule étape est fausse. Désigner laquelle.

Sur la base du module, cinq étudiants suivent les mathématiques et quatre la physique, et kk d'entre eux suivent les deux cours. La question posée : combien d'étudiants sont inscrits à l'un ou à l'autre ?

Exercice 19, Différence

Exercice : écrire puis vérifier

Les inscrits en mathématiques qui ne suivent pas la physique

Écrire l'expression qui donne l'identifiant (idEtudiant) de chaque étudiant inscrit au cours Mathematiques sans être inscrit au cours Physique.

Expression à écrire

Une condition ou une liste d'attributs s'écrit en indice, entre accolades, une chaîne entre apostrophes, un nombre décimal avec un point. Au clavier, et, ou, non, <>, <=, >= et le tiret de la différence conviennent aussi.

Écrire l'expression, puis « Vérifier » : elle est calculée sur 3 cas, dont 1 caché, et comparée à la correction calculée sur les mêmes tables.

Les tables du cas « quatre inscriptions seulement »
Inscription
idEtudiantidCoursnote
1317
2314
2411
3412

Les autres tables sont celles du cours.

En SQL, EXCEPT traduit − de la même façon que UNION traduit ∪. SQLite, PostgreSQL et SQL Server le connaissent, et MySQL depuis sa version 8.0.31.

Exercice : écrire puis vérifier

La même différence, en SQL

Écrire en SQL la requête de l'exercice : l'identifiant de chaque étudiant inscrit au cours Mathematiques sans être inscrit au cours Physique. Les cours se désignent par leur intitulé.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

L'exercice Différence pour dire « sans », sur la page Exercices, s'exerce au même opérateur.

Vérification rapideon peut se reprendre

π_{ville}(Etudiant) et SELECT ville FROM Etudiant diffèrent sur quoi ?

Partie 4, Arbres algébriques

Représenter chaque requête SQL sous forme d'arbre algébrique. Rappel : les feuilles sont les tables, les nœuds internes sont les opérations, et la racine est le résultat final. L'arbre se lit de bas en haut.

Ces exercices reprennent, eux aussi, L'algèbre relationnelle et ses arbres. Sur un arbre, la taille de chaque résultat intermédiaire devient visible, et donc le coût. Les deux premiers arbres se vérifient : l'expression écrite dessine le sien. Les trois suivants sortent de ce que le moteur calcule, ou demandent de juger un coût : ils gardent un corrigé replié.

Exercice 20, Arbre simple (sélection + projection)

requete.sql
Résultat
>_ Prêt à exécuter…
Exercice : écrire puis vérifier

L'arbre d'une sélection suivie d'une projection

Écrire l'expression d'algèbre relationnelle de la requête ci-dessus. Son arbre se dessine sous la zone de saisie à chaque vérification.

Expression à écrire

Une condition ou une liste d'attributs s'écrit en indice, entre accolades, une chaîne entre apostrophes, un nombre décimal avec un point. Au clavier, et, ou, non, <>, <=, >= et le tiret de la différence conviennent aussi.

Écrire l'expression, puis « Vérifier » : elle est calculée sur 3 cas, dont 1 caché, et comparée à la correction calculée sur les mêmes tables.

Les tables du cas « une étudiante née le 1er janvier 2003 tout juste »
Etudiant
idEtudiantnomprenomdateNaissanceemailvilleidClasseactif
2DialloAmine2003-11-02amine.diallo@ecole.frLyon11
6BernardYanis2002-09-08NULLParis21
11RoyLina2003-01-01NULLLyon11

Les autres tables sont celles du cours.

L'exercice Sélection puis projection, sur la page Exercices, pose le même arbre sur une autre table.

Exercice 21, Arbre avec LIKE

requete.sql
Résultat
>_ Prêt à exécuter…

Les lignes de l'arbre au LIKE

  • 1.

    Sur la base du module, combien de lignes la sélection garde-t-elle ?

  • 2.

    Un second étudiant nommé Martin s'inscrit. Combien de lignes la projection rend-elle alors ?

Afficher la correction
Arbre algébrique
      π_{nom}
         |
  σ_{nom LIKE 'M%'}
         |
      Etudiant

Se lit de bas en haut : les feuilles sont les tables, chaque nœud une opération appliquée au résultat du niveau inférieur.

LIKE 'M%' s'écrit en algèbre avec la même notation de sélection : la condition reste une condition sur les attributs de la relation. Le moteur des figures ne connaît pas LIKE, d'où cet arbre dessiné à la main. La sélection garde Martin, Moreau et Marchand. La requête SQL, elle, ne dédoublonne pas : avec un second Martin, elle rendrait quatre lignes, et sa traduction fidèle serait SELECT DISTINCT nom.

Exercice 22, Arbre avec BETWEEN

requete.sql
Résultat
>_ Prêt à exécuter…
Exercice : écrire puis vérifier

BETWEEN, sans BETWEEN

Écrire l'expression d'algèbre relationnelle de la requête ci-dessus. L'algèbre n'a pas d'opérateur BETWEEN.

Expression à écrire

Une condition ou une liste d'attributs s'écrit en indice, entre accolades, une chaîne entre apostrophes, un nombre décimal avec un point. Au clavier, et, ou, non, <>, <=, >= et le tiret de la différence conviennent aussi.

Écrire l'expression, puis « Vérifier » : elle est calculée sur 3 cas, dont 1 caché, et comparée à la correction calculée sur les mêmes tables.

Les tables du cas « trois cours à 20, 40 et 41 heures »
Cours
idCoursintitulevolumeHorairecoefficientidEnseignant
6Statistiques1813
8Chimie201NULL
9Optique401NULL
10Geologie411NULL

Les autres tables sont celles du cours.

Exercice 23, Arbre avec jointure et optimisation

Représenter en arbre la requête suivante, puis proposer une version optimisée :

requete.sql
Résultat
>_ Prêt à exécuter…

Ce que coûte chaque arbre

  • 1.

    Combien de lignes la jointure du haut de l'arbre non optimisé construit-elle, avant la sélection ?

  • 2.

    Combien de lignes la sélection en garde-t-elle ?

  • 3.

    Dans l'arbre optimisé, où la sélection descend sur Cours et où la jointure qui en part est faite d'abord, combien de lignes compte la plus grosse jointure ?

Afficher la correction

Arbre non optimisé :

Cliquer sur un nœud pour voir la relation qu'il produit.

π nom, intituleπ nom, intituleσ intitule = 'Informatique'σ intitule = 'Informatique'⨝ Inscription.idCours = Cours…⨝ Inscription.idCours = Cours.idCours⨝ Etudiant.idEtudiant = Inscr…⨝ Etudiant.idEtudiant = Inscription.idEtudiantEtudiantEtudiantInscriptionInscriptionCoursCours
π nom, intitule3 lignes · 2 attributs
nomintitule
MartinInformatique
MoreauInformatique
NguyenInformatique
Version non optimisée : les deux jointures d'abord, la sélection ensuite.

Arbre optimisé (sélection poussée vers les feuilles) :

Cliquer sur un nœud pour voir la relation qu'il produit.

π nom, intituleπ nom, intitule⨝ Etudiant.idEtudiant = Inscr…⨝ Etudiant.idEtudiant = Inscription.idEtudiantEtudiantEtudiant⨝ Inscription.idCours = Cours…⨝ Inscription.idCours = Cours.idCoursInscriptionInscriptionσ intitule = 'Informatique'σ intitule = 'Informatique'CoursCours
π nom, intitule3 lignes · 2 attributs
nomintitule
MartinInformatique
MoreauInformatique
NguyenInformatique
Version optimisée : la sélection descend sur la feuille Cours, et la jointure qui en part est faite d'abord.
À manipuler
Cliquer sur la jointure du haut de chacun des deux arbres : 25 lignes dans le premier, 3 dans le second. Cliquer ensuite sur la jointure du bas du second : 3 lignes encore. Les deux arbres rendent les trois mêmes lignes à la racine.

Filtrer Cours avant la jointure le réduit à une ligne, et les deux jointures ne portent plus que sur 3 lignes au lieu de 25. L'ordre des jointures se choisit donc lui aussi : descendre la sélection ne suffit pas si la première jointure reste celle des deux grandes tables. L'exercice Pousser la sélection, sur la page Exercices, fait mesurer le même gain.

Exercice 24, Arbre avec agrégation

requete.sql
Résultat
>_ Prêt à exécuter…

Les lignes de l'arbre d'agrégation

  • 1.

    Sur la base du module, combien de lignes la jointure construit-elle ?

  • 2.

    Combien de groupes l'agrégation forme-t-elle ?

  • 3.

    Combien de groupes passent le filtre du HAVING ?

Afficher la correction
Arbre algébrique
              π_{intitule, nbInscrits}
                        |
              σ_{COUNT(*) >= 4}    <-- HAVING
                        |
        γ_{idCours, intitule; COUNT(*)}   <-- GROUP BY + agrégat
                        |
         ⨝ (Cours.idCours = Inscription.idCours)
                /               \
             Cours           Inscription

Se lit de bas en haut : les feuilles sont les tables, chaque nœud une opération appliquée au résultat du niveau inférieur.

γ (gamma) représente l'agrégation, GROUP BY et fonction d'agrégat, sous la forme γ_{colonnes de groupe ; agrégats}. De bas en haut : la jointure, 25 lignes ; l'agrégation par cours, sept groupes ; le filtre du HAVING, qui en laisse quatre, Algorithmique et Physique à quatre inscrits, Bases de donnees et Mathematiques à cinq ; la projection.

Le piège : placer le nœud σ du HAVING sous le nœud γ, par analogie avec la règle « pousser les sélections vers les feuilles » de l'exercice 23. Cette règle ne vaut que pour les sélections qui portent sur des colonnes. Celle-ci porte sur COUNT(*), qui n'existe qu'une fois γ franchi. C'est toute la différence entre WHERE et HAVING, lue sur un dessin.

Vérification rapideon peut se reprendre

1.Dans un arbre algébrique, où placer une sélection pour qu'il coûte le moins cher ?

2.SELECT nom, COUNT(*) FROM Etudiant GROUP BY ville pose quel problème ?

Partie 5, Requêtes complexes et imbriquées

Les quatre parties précédentes portaient sur une seule interrogation à la fois. Celle-ci en emboîte, comme le fait le chapitre SQL avancé : une requête a besoin d'un résultat qu'une autre requête calcule. Avant d'écrire une sous-requête, dire ce qu'elle rend, une valeur, une colonne ou une table. Une valeur se compare avec = ou < ; une colonne permet IN ; EXISTS, lui, accepte n'importe quelle sous-requête reliée à la ligne extérieure, et c'est la forme à préférer dès qu'une négation entre en jeu.

Exercice 25, Jointures multiples

Le schéma des employés et de leurs projets, dans la base du module :

Modèle logique de données
Client
idClient
nom
prenom
ville
Employe
idEmploye
nom
prenom
salaire
date_embauche
service
Projet
idProjet
libelle
idClient→ Client
TravailleSur
idEmploye→ Employe
idProjet→ Projet
heures

clé primaire clé étrangère, avec la table visée

Exercice : écrire puis vérifier

Les employés des projets parisiens

Écrire une requête qui renvoie le nom et le prénom de chaque employé qui travaille sur au moins un projet d'un client situé à Paris, chacun une seule fois.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Exercice 26, Sous-requêtes imbriquées

Exercice : écrire puis vérifier

Les cours des étudiants nés après le 1er juin 2004

Écrire une requête qui renvoie l'intitulé de chaque cours suivi par au moins un étudiant né après le 1er juin 2004, chacun une seule fois. Une date s'écrit '2004-06-01'.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Sur la base du cours, deux étudiantes sont nées après la date, Dupond Sophie et Nguyen Elsa, et leurs cours sont six sur sept : seul Statistiques manque. La requête rend les cours qui ont au moins un tel inscrit ; ceux qui n'ont que de tels inscrits demanderaient une négation, comme à l'exercice suivant.

Exercice 27, Double négation (tous les cours)

Exercice : écrire puis vérifier

Les étudiants inscrits à tous les cours, en SQL

Écrire une requête qui renvoie le nom et le prénom de chaque étudiant inscrit à tous les cours de la table Cours.

Sur la base du cours, le résultat est vide : aucun étudiant ne suit les sept cours. La deuxième vérification fait inscrire une étudiante partout, pour que la requête ait quelqu'un à trouver.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Cette double négation est la traduction directe de la division relationnelle de l'exercice 17.

Après l'exercice : restreindre le diviseur, et deux autres écritures

Le bloc ci-dessous reprend la correction, sur la base du cours, où elle rend un résultat vide.

requete.sql
Résultat
>_ Prêt à exécuter…
À manipuler
Restreindre le diviseur : écrire WHERE c.idCours IN (1, 3) AND NOT EXISTS ( à la place de WHERE NOT EXISTS ( dans la sous-requête du milieu, et relancer. Trois étudiants sortent, Martin, Diallo et Dupond : la requête fonctionne, et le résultat vide sur les sept cours était la bonne réponse.

Avec EXCEPT (SQLite, PostgreSQL, SQL Server, et MySQL depuis la version 8.0.31), la sous-requête du milieu devient une différence : les cours de la table, moins ceux de l'étudiant. Il ne doit rien en rester.

requete.sql
Résultat
>_ Prêt à exécuter…

La sous-requête intérieure pourrait s'écrire c.idCours NOT IN (SELECT i.idCours FROM Inscription i WHERE i.idEtudiant = e.idEtudiant), juste ici parce qu'idCours, dans la clé primaire, n'est jamais NULL. Le jour où la liste contient un NULL, NOT IN n'est plus jamais vrai, et l'étudiant concerné est déclaré inscrit à tous les cours ; EXCEPT et les deux NOT EXISTS y résistent.

L'exercice Inscrit à tous, sur la page Exercices, reprend cette double négation.

Exercice 28, Analyse statistique

Trois questions, une requête pour chacune : la note maximale de chaque cours ; les cours dont la moyenne est inférieure à la moyenne générale de toutes les notes ; l'étudiant qui a la meilleure note de toute la base.

Exercice : écrire puis vérifier

La note maximale de chaque cours

Écrire une requête qui renvoie l'intitulé de chaque cours et sa meilleure note, de la plus haute à la plus basse.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Exercice : écrire puis vérifier

Les cours sous la moyenne générale

Écrire une requête qui renvoie l'intitulé et la moyenne, arrondie à deux décimales par ROUND(..., 2), de chaque cours dont la moyenne est strictement inférieure à la moyenne générale de toutes les notes, de la plus basse à la plus haute.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Les deux moyennes ne coïncident que si tous les cours ont le même nombre de notes ; sur la base, Mathematiques en pèse cinq et Statistiques une seule, son second inscrit n'étant pas noté. L'étape suivante refait le calcul de travers.

La moyenne générale, prise de travers

Une seule étape est fausse. Désigner laquelle.

Un cours de mathématiques a nn notes, de moyenne 14 ; un cours de statistiques n'en a qu'une, 10. Il s'agit de trouver la moyenne générale, celle que rend SELECT AVG(note) FROM Inscription, pour lui comparer chaque cours.

Exercice : écrire puis vérifier

La meilleure note de la base, et qui l'a obtenue

Écrire une requête qui renvoie le nom, le prénom et la note de l'étudiant qui a obtenu la meilleure note de toute la base. S'ils sont plusieurs à l'avoir obtenue, la requête les renvoie tous.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

L'exercice Au-dessus de la moyenne, sur la page Exercices, compare lui aussi chaque ligne à une valeur que calcule une sous-requête.

Exercice 29, Sous-requête corrélée

Exercice : écrire puis vérifier

Le meilleur de chaque cours

Écrire une requête qui renvoie, pour chaque cours, le nom, le prénom, l'intitulé du cours et la note de l'étudiant qui y a obtenu la meilleure note ; en cas d'ex æquo, tous.

Le résultat se range par intitulé, puis par nom.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

Sans le ORDER BY, l'ordre des lignes n'est fixé par rien, et MySQL ne rend pas le même que la page.

Après l'exercice : la même requête avec WITH

WITH donne un nom à une sous-requête, que la suite de la requête utilise comme une table :

requete.sql
Résultat
>_ Prêt à exécuter…

L'exercice Le projet principal de chacun, sur la page Exercices, pose la même question sur les employés et leurs projets.

Exercice 30, EXISTS vs IN

Exercice : écrire puis vérifier

Les étudiants qui ont une note sous 10, en SQL

Écrire une requête qui renvoie le nom et le prénom de chaque étudiant qui a au moins une inscription notée strictement sous 10, chacun une seule fois.

« Exécuter » montre ce que rend la requête ; « Vérifier » compare son résultat à celui attendu, sur 3 cas, dont 1 caché.

IN, EXISTS et la jointure avec DISTINCT rendent ici les mêmes cinq étudiants. Les deux premières ne parcourent qu'Etudiant, et ne peuvent pas produire de doublon ; la troisième le peut.

ApprocheAvantagesInconvénients
INLisible, intuitifNOT IN se vide si la sous-requête rend un NULL
EXISTSRésiste aux NULL en négationSyntaxe plus verbeuse
JOINDonne accès aux colonnes de la table jointeNécessite DISTINCT pour éviter les doublons

Les performances se valent le plus souvent : l'optimiseur réécrit les deux formes, et sur cet exercice MySQL exécute IN et EXISTS selon le même plan, que EXPLAIN affiche (voir Exploiter une base). EXISTS sert à vérifier une existence, JOIN quand des colonnes de la table jointe sont nécessaires.

Le piège, en négatif : tant que la question est positive, IN et EXISTS donnent le même résultat ; la négation les sépare. Les trois requêtes suivantes cherchent les inscriptions dont la note ne figure pas parmi celles du cours 2, dont un inscrit n'est pas encore noté.

Un NULL dans la liste

  • 1.

    Combien de lignes rend la requête en NOT IN sur la base du module ?

  • 2.

    Combien en rend-elle une fois la sous-requête débarrassée de son NULL ?

  • 3.

    Combien en rend la version en NOT EXISTS ?

requete.sql
Résultat
>_ Prêt à exécuter…

Elle ne rend aucune ligne, sans erreur ni avertissement. La sous-requête rend quatre notes, 16.5, 14.5, 10.5 et un NULL : note NOT IN (16.5, 14.5, 10.5, NULL) demande d'affirmer que la note diffère d'une valeur inconnue, la condition vaut inconnu, et WHERE ne garde que ce qui est vrai.

requete.sql
Résultat
>_ Prêt à exécuter…

Vingt lignes cette fois : le passage de zéro à vingt tient à une seule valeur absente. Une requête juste pendant des mois devient silencieusement vide le jour où une saisie est laissée en blanc. NOT EXISTS résiste, parce qu'il teste l'existence d'une ligne, pas l'égalité avec une valeur :

requete.sql
Résultat
>_ Prêt à exécuter…

Vingt-deux lignes : les vingt précédentes, plus les deux inscriptions dont la note est elle-même absente, qu'aucune note du cours 2 n'égale.

Vérification rapideon peut se reprendre

1.Sur la base du module, une jointure de Etudiant, Inscription et Cours rend 175 lignes. Est-ce normal ?

2.Quel test faut-il pour trouver les lignes dont une colonne n'a aucune valeur ?

Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?