Bases de données relationnelles et SQL
Un site de billetterie affiche « Il reste 1 place » pour un concert à Lyon. Deux personnes cliquent sur « Réserver » en même temps. Qui obtient la place ? Pour que les données restent cohérentes, il faut les organiser avec méthode et les confier à un logiciel spécialisé. C'est l'objet de ce chapitre, qui est un classique de l'épreuve de spécialité NSI du bac.
Le modèle relationnel
Dans une base de données relationnelle, les données sont rangées dans des relations, que l'on représente par des tableaux.
Exemple de relation :
| num | nom | prenom | classe |
|---|---|---|---|
| 1 | Martin | Léa | TG1 |
| 2 | Bernard | Hugo | TG2 |
Son schéma s'écrit : ELEVE(num, nom, prenom, classe). Elle a 4 attributs. Avec les deux lignes ci-dessus, elle compte 2 enregistrements.
On distingue la structure de la base (le schéma, les domaines) de son contenu (les enregistrements, qui changent au cours du temps).
Le système de gestion de bases de données (SGBD) refuse un enregistrement dont la clef primaire existe déjà : c'est la contrainte d'unicité. Il refuse aussi une clef étrangère qui ne référence aucun enregistrement existant : c'est la contrainte d'intégrité référentielle.
Un lycée gère ses élèves avec la relation ELEVE, dont la clef primaire est num. | num | nom | prenom | classe | |---|---|---|---| | 1 | Martin | Léa | TG1 | | 2 |…
Un lycée gère ses élèves avec la relation ELEVE, dont la clef primaire est num.
| num | nom | prenom | classe |
|---|---|---|---|
| 1 | Martin | Léa | TG1 |
| 2 | Bernard | Hugo | TG2 |
| 3 | Petit | Inès | TG1 |
| 4 | Moreau | Tom | TG3 |
-
Donner le nombre d'attributs et le nombre d'enregistrements de cette relation, puis écrire son schéma relationnel.
-
Indiquer un domaine possible pour l'attribut
numet un domaine possible pour l'attributclasse. -
On exécute la requête suivante.
INSERT INTO ELEVE VALUES (3, 'Roux', 'Paul', 'TG2');
Expliquer pourquoi le système de gestion de bases de données refuse cette insertion.
- Écrire une requête SQL qui renvoie les noms des élèves de la classe TG1, puis donner son résultat.
Redondance et anomalies
Regardons une boutique qui range tout dans une seule relation :
| num_cmd | client | adresse_client | produit | prix |
|---|---|---|---|---|
| 101 | Martin | 12 rue Pasteur | Cahier | 2,50 |
| 102 | Martin | 12 rue Pasteur | Stylo | 1,20 |
L'adresse de Martin est écrite deux fois : c'est une redondance. Elle provoque des anomalies :
-
Mise à jour : si Martin déménage, il faut modifier toutes ses lignes ; en oublier une rend la base incohérente.
-
Insertion : on ne peut pas enregistrer un client qui n'a pas encore commandé, car il n'y a pas de numéro de commande.
-
Suppression : en supprimant la seule commande d'un client, on perd aussi son adresse.
La solution est de répartir les données en plusieurs relations reliées par des clefs étrangères : CLIENT(id_client, nom, adresse) et COMMANDE(num_cmd, id_client, produit, prix). Chaque information n'est alors écrite qu'une seule fois.
Une boutique en ligne stocke ses commandes dans une unique relation. COMMANDE(num_cmd, client, adresse_client, produit, prix) | num_cmd | client | adresse_client |…
Une boutique en ligne stocke ses commandes dans une unique relation.
COMMANDE(num_cmd, client, adresse_client, produit, prix)
| num_cmd | client | adresse_client | produit | prix |
|---|---|---|---|---|
| 101 | Martin | 12 rue Pasteur | Cahier | 2,50 |
| 102 | Martin | 12 rue Pasteur | Stylo | 1,20 |
| 103 | Leroy | 5 avenue Foch | Cahier | 2,50 |
-
Repérer les redondances présentes dans cette relation.
-
Pour chacune des situations suivantes, décrire l'anomalie rencontrée.
a) Mise à jour : le client Martin déménage.
b) Insertion : on souhaite enregistrer un nouveau client qui n'a encore passé aucune commande.
c) Suppression : on supprime la commande 103.
-
Proposer un schéma relationnel à trois relations,
CLIENT,PRODUITetCOMMANDE, qui supprime ces anomalies. Souligner les clefs primaires et indiquer les clefs étrangères. -
Indiquer, dans le nouveau schéma, ce que devient la mise à jour de l'adresse de Martin.
Interroger avec SQL
SQL est le langage d'interrogation des bases relationnelles. Une requête de sélection a cette forme :
SELECT attributs
FROM relation
WHERE condition
ORDER BY attribut;
-
SELECTchoisit les colonnes,*signifie « toutes ». -
FROMindique la relation. -
WHEREfiltre les lignes (=,<,>=,<>,AND,OR). -
ORDER BYtrie (par défaut croissant,DESCpour décroissant). -
DISTINCTsupprime les doublons. -
Les fonctions d'agrégation
COUNT,SUM,AVG,MIN,MAXcalculent une valeur sur l'ensemble des lignes sélectionnées.
Les chaînes de caractères s'écrivent entre apostrophes : 'Dubois'. Au programme, il n'y a ni GROUP BY ni HAVING.
Un cinéma de quartier gère la relation FILM. | id | titre | realisateur | annee | duree | |---|---|---|---|---| | 1 | Le Phare | Dubois | 2015 | 95 | | 2 | Rue des Lilas…
Un cinéma de quartier gère la relation FILM.
| id | titre | realisateur | annee | duree |
|---|---|---|---|---|
| 1 | Le Phare | Dubois | 2015 | 95 |
| 2 | Rue des Lilas | Lemaire | 2018 | 110 |
| 3 | Nuit blanche | Dubois | 2020 | 88 |
| 4 | Le Grand Marché | Garnier | 2018 | 102 |
| 5 | Terres rouges | Lemaire | 2021 | 125 |
La durée est exprimée en minutes. Donner le résultat de chacune des requêtes suivantes.
-
SELECT titre FROM FILM WHERE annee = 2018; -
SELECT titre, duree FROM FILM WHERE realisateur = 'Dubois' ORDER BY duree; -
SELECT COUNT(*) FROM FILM WHERE annee >= 2018; -
SELECT AVG(duree) FROM FILM; -
Écrire une requête qui renvoie les titres des films dont la durée est strictement supérieure à 100 minutes, puis donner son résultat.
Joindre plusieurs relations
Pour afficher le nom d'un adhérent avec le titre du livre emprunté, il faut croiser plusieurs relations grâce aux clefs étrangères : c'est la jointure.
SELECT ADHERENT.nom, LIVRE.titre
FROM EMPRUNT
JOIN ADHERENT ON EMPRUNT.id_adh = ADHERENT.id_adh
JOIN LIVRE ON EMPRUNT.id_livre = LIVRE.id_livre
WHERE ADHERENT.ville = 'Lyon';
JOIN … ON … associe chaque ligne de EMPRUNT à la ligne de l'autre relation qui a la même valeur de clef. On préfixe les attributs par le nom de la relation (ADHERENT.nom) pour éviter toute ambiguïté.
Pour trouver les livres non rendus, on teste la valeur NULL avec IS NULL (jamais avec = NULL) : WHERE date_retour IS NULL.
Une médiathèque utilise une base de données composée de trois relations. LIVRE(id_livre, titre, auteur) | id_livre | titre | auteur | |---|---|---| | 1 | Les Misérables…
Une médiathèque utilise une base de données composée de trois relations.
LIVRE(id_livre, titre, auteur)
| id_livre | titre | auteur |
|---|---|---|
| 1 | Les Misérables | Hugo |
| 2 | Germinal | Zola |
| 3 | Candide | Voltaire |
| 4 | Bel-Ami | Maupassant |
ADHERENT(id_adh, nom, ville)
| id_adh | nom | ville |
|---|---|---|
| 1 | Dupont | Lyon |
| 2 | Leroy | Nantes |
| 3 | Fabre | Lyon |
EMPRUNT(id_adh, id_livre, date_emprunt)
| id_adh | id_livre | date_emprunt |
|---|---|---|
| 1 | 2 | 2025-03-04 |
| 1 | 3 | 2025-03-10 |
| 2 | 2 | 2025-03-12 |
| 3 | 1 | 2025-03-15 |
| 3 | 2 | 2025-03-20 |
-
Identifier les clefs étrangères de la relation
EMPRUNTet les relations auxquelles elles font référence. -
Écrire une requête qui renvoie les noms des adhérents ayant emprunté le livre « Germinal », puis donner son résultat trié par ordre alphabétique.
-
Écrire une requête qui renvoie, sans doublon et par ordre alphabétique, les titres des livres empruntés par des adhérents habitant Lyon, puis donner son résultat.
-
Donner le nombre de lignes renvoyées par la requête de la question 3 si l'on supprime le mot-clef
DISTINCT. -
Écrire une requête qui renvoie le nombre total d'emprunts, puis donner son résultat.
Un lycée stocke les notes de ses élèves dans deux relations. ELEVE(id, nom, classe) | id | nom | classe | |---|---|---| | 1 | Martin | TG1 | | 2 | Petit | TG1 | | 3 |…
Un lycée stocke les notes de ses élèves dans deux relations.
ELEVE(id, nom, classe)
| id | nom | classe |
|---|---|---|
| 1 | Martin | TG1 |
| 2 | Petit | TG1 |
| 3 | Moreau | TG2 |
NOTE(id_eleve, matiere, valeur)
| id_eleve | matiere | valeur |
|---|---|---|
| 1 | NSI | 15 |
| 1 | Maths | 12 |
| 2 | NSI | 11 |
| 2 | Maths | 14 |
| 3 | NSI | 17 |
| 3 | Maths | 9 |
Pour chacune des questions suivantes, écrire la requête SQL demandée, puis donner son résultat.
-
Calculer la moyenne des notes de NSI de l'ensemble des élèves. Arrondir au centième.
-
Donner le nom et la note de NSI des élèves de la classe TG1, par ordre décroissant de note.
-
Déterminer le nombre de notes strictement supérieures à 12.
-
Déterminer la meilleure note de mathématiques.
-
Calculer la moyenne des notes de NSI des élèves de la classe TG1.
Une médiathèque gère ses prêts avec les relations suivantes. L'attribut date_retour vaut NULL tant que le livre n'a pas été rendu, et le test se fait avec IS NULL.…
Une médiathèque gère ses prêts avec les relations suivantes. L'attribut date_retour vaut NULL tant que le livre n'a pas été rendu, et le test se fait avec IS NULL.
LIVRE(id_livre, titre, auteur)
| id_livre | titre | auteur |
|---|---|---|
| 1 | Les Misérables | Hugo |
| 2 | Germinal | Zola |
| 3 | Candide | Voltaire |
ADHERENT(id_adh, nom, ville)
| id_adh | nom | ville |
|---|---|---|
| 1 | Dupont | Lyon |
| 2 | Leroy | Nantes |
| 3 | Fabre | Lyon |
EMPRUNT(id_adh, id_livre, date_emprunt, date_retour)
| id_adh | id_livre | date_emprunt | date_retour |
|---|---|---|---|
| 1 | 2 | 2025-03-04 | 2025-03-18 |
| 1 | 3 | 2025-03-10 | NULL |
| 2 | 2 | 2025-03-12 | NULL |
| 3 | 1 | 2025-03-15 | 2025-03-29 |
| 3 | 2 | 2025-03-20 | NULL |
-
Écrire une requête qui renvoie le nom de l'adhérent et le titre du livre pour chaque emprunt non rendu, puis donner son résultat trié par nom.
-
Écrire une requête qui renvoie, sans doublon, les noms des adhérents ayant emprunté au moins un livre de Zola, puis donner son résultat trié par ordre alphabétique.
-
Écrire une requête qui enregistre le retour du livre 2 par l'adhérent 2 le 2025-04-01, puis donner le nombre d'emprunts non rendus après cette mise à jour.
-
On exécute
INSERT INTO EMPRUNT VALUES (4, 1, '2025-04-02', NULL);. Expliquer pourquoi un système de gestion de bases de données qui vérifie l'intégrité référentielle refuse cette insertion.
Un réseau régional de trains TER est décrit par deux relations. L'attribut duree_min est la durée du trajet en minutes. Les attributs gare_depart et gare_arrivee sont…
Un réseau régional de trains TER est décrit par deux relations. L'attribut duree_min est la durée du trajet en minutes. Les attributs gare_depart et gare_arrivee sont des clefs étrangères qui référencent GARE.
GARE(id_gare, nom, ville)
| id_gare | nom | ville |
|---|---|---|
| 1 | Dijon-Ville | Dijon |
| 2 | Beaune | Beaune |
| 3 | Chalon-sur-Saône | Chalon |
| 4 | Mâcon-Ville | Mâcon |
TRAJET(id_trajet, gare_depart, gare_arrivee, duree_min)
| id_trajet | gare_depart | gare_arrivee | duree_min |
|---|---|---|---|
| 1 | 1 | 2 | 25 |
| 2 | 2 | 3 | 20 |
| 3 | 3 | 4 | 35 |
| 4 | 1 | 3 | 40 |
| 5 | 1 | 4 | 70 |
-
Expliquer pourquoi la relation
GAREdoit être utilisée deux fois dans une requête qui affiche le nom de la gare de départ et le nom de la gare d'arrivée de chaque trajet. -
Écrire une requête qui renvoie, pour chaque trajet dont la durée est strictement inférieure à 40 minutes, le nom de la gare de départ, le nom de la gare d'arrivée et la durée. On utilisera deux alias de la relation
GARE. Donner le résultat par ordre croissant de durée. -
Donner le résultat de
SELECT SUM(duree_min) FROM TRAJET WHERE id_trajet <= 3;. -
Les trajets 1, 2 et 3 forment un itinéraire de Dijon-Ville à Mâcon-Ville avec arrêts. Comparer sa durée totale à celle du trajet direct 5.
-
Écrire une requête qui supprime le trajet 4, puis donner le nombre de lignes de la relation
TRAJETaprès cette suppression.
Modifier les données
Trois requêtes modifient le contenu de la base :
INSERT INTO PRODUIT VALUES (4, 'Règle', 0.90, 60);
UPDATE PRODUIT SET prix = 1.50 WHERE nom = 'Stylo';
DELETE FROM PRODUIT WHERE stock < 30;
-
INSERT INTOajoute un enregistrement (les valeurs suivent l'ordre des attributs). -
UPDATE … SET … WHEREmodifie des valeurs existantes. -
DELETE FROM … WHEREsupprime des lignes.
En SQL, le séparateur décimal est le point (0.90) et non la virgule, contrairement à l'écriture française habituelle (0,90).
Pour augmenter un stock, on peut utiliser l'ancienne valeur : UPDATE PRODUIT SET stock = stock + 10 WHERE ref = 1;.
Une papeterie utilise la relation PRODUIT suivante (prix en euros). | ref | nom | prix | stock | |---|---|---|---| | 1 | Cahier | 2,50 | 40 | | 2 | Stylo | 1,20 | 100 |…
Une papeterie utilise la relation PRODUIT suivante (prix en euros).
| ref | nom | prix | stock |
|---|---|---|---|
| 1 | Cahier | 2,50 | 40 |
| 2 | Stylo | 1,20 | 100 |
| 3 | Classeur | 4,80 | 25 |
On exécute successivement les trois requêtes suivantes.
UPDATE PRODUIT SET prix = 1.50 WHERE nom = 'Stylo';
DELETE FROM PRODUIT WHERE stock < 30;
INSERT INTO PRODUIT VALUES (4, 'Règle', 0.90, 60);
-
Donner le contenu de la relation
PRODUITaprès chacune de ces requêtes. -
Écrire une requête qui augmente de 10 unités le stock du produit de référence 1.
-
Indiquer, parmi
UPDATE,DELETE,INSERTetSELECT, celles qui modifient le contenu de la base.
Les services d'un SGBD
Un SGBD n'est pas qu'un simple fichier : il rend quatre services principaux (sans qu'on ait à connaître son fonctionnement interne).
-
Persistance : les données restent enregistrées après l'arrêt du programme.
-
Gestion des accès concurrents : plusieurs utilisateurs peuvent lire et écrire en même temps sans corrompre les données.
-
Efficacité du traitement des requêtes : même sur de très gros volumes.
-
Sécurisation des accès : chaque utilisateur n'a que les droits qui lui sont accordés.
Un site de réservation de places de concert enregistre ses données dans un système de gestion de bases de données. La relation PLACE contient notamment une ligne dont…
Un site de réservation de places de concert enregistre ses données dans un système de gestion de bases de données. La relation PLACE contient notamment une ligne dont l'attribut stock vaut 1 pour la référence 7.
Deux clients, Alice et Bob, cherchent à réserver cette dernière place au même moment. Le programme de chacun exécute les trois étapes suivantes.
-
Lire la valeur de
stockpour la référence 7. -
Si cette valeur est supérieure à 0, calculer
stock - 1. -
Écrire la nouvelle valeur dans la base.
Les opérations s'entrelacent ainsi : Alice exécute l'étape 1, Bob exécute l'étape 1, Alice exécute les étapes 2 et 3, puis Bob exécute les étapes 2 et 3.
-
Donner la valeur de
stockà la fin de l'exécution et le nombre de places réellement vendues. Expliquer le problème rencontré. -
Citer le service d'un système de gestion de bases de données qui a pour rôle d'éviter ce problème.
-
On propose la requête unique suivante.
UPDATE PLACE SET stock = stock - 1 WHERE ref = 7 AND stock > 0;
Expliquer pourquoi son exécution par un système de gestion de bases de données qui garantit l'absence d'accès concurrents conflictuels résout le problème.
-
La relation
CLIENTdu site contient les attributsnom,prenom,email,date_naissance,adresse,numero_securite_socialeethistorique_navigation. Le seul usage prévu est l'envoi des billets par courriel.a) Indiquer les attributs qui ne sont pas nécessaires à cet usage.
b) Justifier ce choix par un principe de minimisation des données personnelles prévu par le RGPD.
L'essentiel
-
Une base relationnelle est un ensemble de relations (tableaux). Chaque relation a des attributs (colonnes) avec un domaine, et des enregistrements (lignes).
-
La clef primaire identifie un enregistrement. La clef étrangère référence la clef primaire d'une autre relation.
-
La redondance cause des anomalies de mise à jour, d'insertion et de suppression. On l'évite en séparant les données en plusieurs relations.
-
SELECT … FROM … WHERE … ORDER BY, avecDISTINCT,COUNT,SUM,AVG,MIN,MAXetJOIN … ON …. -
INSERT,UPDATEetDELETEmodifient le contenu. Toujours soigner leWHERE. -
Un SGBD assure la persistance, la gestion des accès concurrents, l'efficacité des requêtes et la sécurisation des accès.
Retour au début : la dernière place de concert est attribuée à une seule personne parce que le SGBD gère les accès concurrents par des transactions.