Modèle relationnel et langage SQL
La médiathèque de Nantes gère ses adhérents et ses prêts. Si elle note dans un seul grand tableau le nom, l'adresse et la ville de chaque adhérent à chaque emprunt, que se passe-t-il quand Léa déménage ? Il faut corriger des dizaines de lignes, et on risque d'en oublier une. Les bases de données relationnelles ont été inventées pour éviter ce genre de problème. À la fin de cette page, tu sauras les organiser et les interroger.
Tables, attributs et clefs
Une base de données relationnelle range l'information dans des relations, que l'on représente par des tables. Chaque ligne décrit un objet (un élève, un livre…), chaque colonne décrit une de ses caractéristiques.
Exemple de schéma, la clef primaire étant soulignée en pratique, ici écrite en premier : Adherent(num, nom, ville) et Emprunt(id, num_adherent, titre, date_emprunt).
La clef étrangère garantit la cohérence : on ne peut pas enregistrer un emprunt pour un numéro d'adhérent qui n'existe pas. C'est le SGBD (système de gestion de bases de données) qui le vérifie. Il assure aussi la persistance des données, la gestion des accès simultanés, l'efficacité des requêtes et la sécurisation des accès.
Une relation Eleve(id, nom, prenom, classe) a pour clef primaire id. a) Expliquer ce qu'est une relation, un attribut et un domaine, en prenant des exemples dans Eleve.…
Une relation Eleve(id, nom, prenom, classe) a pour clef primaire id.
- a) Expliquer ce qu'est une relation, un attribut et un domaine, en prenant des exemples dans
Eleve.
- b) Expliquer le rôle d'une clef primaire et pourquoi deux élèves ne peuvent pas avoir le même
id.
- c) Donner le schéma de la relation.
Interroger : SELECT, FROM, WHERE
SQL est un langage déclaratif : on décrit ce qu'on veut obtenir, pas comment le calculer. Une requête de sélection a la forme :
SELECT attributs
FROM table
WHERE condition
ORDER BY attribut;
Prenons Livre(id, titre, auteur, annee, prix) :
| id | titre | auteur | annee | prix |
|---|---|---|---|---|
| 1 | Germinal | Zola | 1885 | 7,50 |
| 2 | Candide | Voltaire | 1759 | 5,00 |
| 3 | Nana | Zola | 1880 | 8,00 |
(Dans les exemples de cette page, on écrit les nombres décimaux avec la virgule, comme en français : 7,50.)
Quelques outils utiles :
-
Comparaisons :
=,<>,<,<=,>,>=; connecteursAND,OR,NOT. -
ORDER BY prixtrie par prix croissant ;ORDER BY prix DESCpar prix décroissant. -
DISTINCTsupprime les doublons :SELECT DISTINCT auteur FROM Livre; -
LIMIT 3ne garde que les trois premières lignes du résultat. -
SELECT *renvoie toutes les colonnes.
On considère la table Livre(id, titre, auteur, annee, prix) contenant, entre autres, les livres suivants : (1, "Germinal", "Zola", 1885, 7.50), (2, "Candide",…
On considère la table Livre(id, titre, auteur, annee, prix) contenant, entre autres, les livres suivants : (1, "Germinal", "Zola", 1885, 7.50), (2, "Candide", "Voltaire", 1759, 5.00), (3, "Nana", "Zola", 1880, 8.00).
- a) Écrire la requête SQL qui renvoie les titres des livres de Zola.
- b) Écrire la requête qui renvoie tous les livres triés par prix croissant.
- c) Donner le résultat de la requête
SELECT titre FROM Livre WHERE annee < 1882;.
Modifier : INSERT, UPDATE, DELETE
Les requêtes de mise à jour changent le contenu de la base.
INSERT INTO Livre (id, titre, auteur, annee, prix)
VALUES (5, 'Bel-Ami', 'Maupassant', 1885, 6.50);
UPDATE Livre SET prix = 5.50 WHERE id = 2;
DELETE FROM Livre WHERE annee < 1700;
Avec la table Livre(id, titre, auteur, annee, prix) de l'exercice précédent : a) Écrire la requête qui ajoute le livre (4, "Au bonheur des dames", "Zola", 1883, 9.00).…
Avec la table Livre(id, titre, auteur, annee, prix) de l'exercice précédent :
- a) Écrire la requête qui ajoute le livre (4, "Au bonheur des dames", "Zola", 1883, 9.00).
- b) Écrire la requête qui passe le prix du livre d'
id2 à 6,00.
- c) Écrire la requête qui supprime les livres publiés avant 1800.
Agréger et regrouper
Pour faire des calculs sur plusieurs lignes, on utilise des fonctions d'agrégation : COUNT(*) (nombre de lignes), SUM(x) (somme), AVG(x) (moyenne), MIN(x), MAX(x). Elles renvoient une seule valeur.
Table Vente(id, produit, magasin, quantite, prix_unitaire) :
| id | produit | magasin | quantite | prix_unitaire |
|---|---|---|---|---|
| 1 | baguette | Lyon | 40 | 1,10 |
| 2 | croissant | Lyon | 25 | 1,20 |
| 3 | baguette | Lille | 30 | 1,10 |
SELECT SUM(quantite) FROM Vente; renvoie 95. On peut aussi calculer sur une expression : SUM(quantite * prix_unitaire).
GROUP BY forme des groupes de lignes qui ont la même valeur, et l'agrégation s'applique à chaque groupe.
WHERE filtre les lignes avant le regroupement. HAVING filtre les groupes après, donc c'est le seul à pouvoir porter sur un résultat d'agrégation.
SELECT magasin, SUM(quantite)
FROM Vente
GROUP BY magasin
HAVING SUM(quantite) > 50;
Cette requête ne renvoie que Lyon. Écrire WHERE SUM(quantite) > 50 provoquerait une erreur : à ce stade, les sommes ne sont pas encore calculées.
Pour obtenir les plus grandes valeurs, on trie en ordre décroissant puis on limite : ORDER BY quantite DESC LIMIT 3.
La table Vente(id, produit, magasin, quantite, prix_unitaire) recense les ventes d'une chaîne de boulangeries. a) Écrire la requête qui calcule le chiffre d'affaires…
La table Vente(id, produit, magasin, quantite, prix_unitaire) recense les ventes d'une chaîne de boulangeries.
- a) Écrire la requête qui calcule le chiffre d'affaires total ($\text{quantité} \times \text{prix unitaire}$).
- b) Écrire la requête qui donne, pour chaque magasin, la quantité totale vendue.
- c) Écrire la requête qui renvoie le prix unitaire moyen des ventes du produit « baguette ».
- d) Écrire la requête qui renvoie les trois ventes de plus grande quantité.
Relier les tables : les jointures
Les informations sont réparties dans plusieurs tables ; une jointure les recombine en suivant les clefs étrangères.
SELECT Adherent.nom, Emprunt.titre
FROM Adherent
JOIN Emprunt ON Adherent.num = Emprunt.num_adherent;
JOIN … ON … associe chaque ligne de Adherent aux lignes de Emprunt pour lesquelles la condition est vraie. On préfixe les attributs par le nom de la table (Adherent.nom) pour lever toute ambiguïté.
On peut combiner jointure, WHERE, AVG, HAVING… en suivant toujours le même ordre d'écriture : SELECT, FROM, JOIN, WHERE, GROUP BY, HAVING, ORDER BY.
Pour trouver les éléments sans correspondance (par exemple les adhérents qui n'ont rien emprunté), une jointure ne suffit pas, car elle ne garde que les lignes appariées. On utilise une sous-requête avec NOT IN :
SELECT nom FROM Adherent
WHERE num NOT IN (SELECT num_adherent FROM Emprunt);
Une médiathèque de Nantes utilise les tables Adherent(num, nom, ville) et Emprunt(id, num_adherent, titre, date_emprunt), où num_adherent est une clef étrangère vers…
Une médiathèque de Nantes utilise les tables Adherent(num, nom, ville) et Emprunt(id, num_adherent, titre, date_emprunt), où num_adherent est une clef étrangère vers Adherent(num).
- a) Expliquer le rôle de la clef étrangère.
- b) Écrire la requête qui renvoie le nom des adhérents et les titres qu'ils ont empruntés.
- c) Écrire la requête qui renvoie le nombre d'emprunts de chaque adhérent (numéro et nombre).
- d) Écrire la requête qui renvoie sans doublon les villes des adhérents ayant emprunté au moins un livre.
Un lycée gère les relations Eleve(id, nom, classe), Matiere(code, intitule) et Note(id_eleve, code_matiere, valeur). La clef primaire de Note est le couple (id_eleve,…
Un lycée gère les relations Eleve(id, nom, classe), Matiere(code, intitule) et Note(id_eleve, code_matiere, valeur). La clef primaire de Note est le couple (id_eleve, code_matiere).
- a) Donner les clefs étrangères du schéma.
- b) Écrire la requête qui renvoie, pour chaque élève (nom), sa moyenne en « Mathématiques ».
- c) Écrire la requête qui renvoie les noms des élèves de classe « T1 » dont la moyenne en « NSI » dépasse 14.
- d) Expliquer pourquoi l'insertion d'une note avec un
id_eleveinexistant doit être refusée et par quel mécanisme.
Soit la table Film(id, titre, realisateur, annee) et la table Projection(id_film, salle, heure) où id_film est une clef étrangère. a) Écrire la requête qui renvoie les…
Soit la table Film(id, titre, realisateur, annee) et la table Projection(id_film, salle, heure) où id_film est une clef étrangère.
- a) Écrire la requête qui renvoie les titres des films projetés dans au moins deux salles différentes.
- b) Écrire la requête qui renvoie les réalisateurs dont aucun film n'est projeté.
- c) Expliquer la différence entre
WHEREetHAVINGen justifiant l'usage nécessaire de l'un d'eux dans la question a).
Bien concevoir : redondance et anomalies
Reprenons notre médiathèque, avec une seule table :
| num_pret | nom | ville | titre |
|---|---|---|---|
| 1 | Léa | Nantes | Germinal |
| 2 | Léa | Nantes | Nana |
| 3 | Hugo | Rezé | Candide |
La ville de Léa est écrite deux fois : c'est de la redondance. Elle provoque trois anomalies :
-
mise à jour : si Léa déménage, il faut modifier toutes ses lignes, sinon la base devient incohérente ;
-
insertion : on ne peut pas enregistrer un nouvel adhérent qui n'a encore rien emprunté ;
-
suppression : si on supprime le seul prêt de Hugo, on perd aussi les informations sur Hugo.
Remède : séparer les informations en relations, chacune décrivant un seul type d'objet, reliées par des clefs étrangères :
-
Adherent(num, nom, ville), clef primairenum; -
Livre(code, titre), clef primairecode; -
Pret(num_pret, num_adherent, code_livre), clef primairenum_pret, clefs étrangèresnum_adherent→Adherent(num)etcode_livre→Livre(code).
Chaque information n'est plus écrite qu'une seule fois. Les tables se créent avec CREATE TABLE :
CREATE TABLE Adherent (
num INTEGER PRIMARY KEY,
nom TEXT,
ville TEXT
);
CREATE TABLE Pret (
num_pret INTEGER PRIMARY KEY,
num_adherent INTEGER,
code_livre INTEGER,
FOREIGN KEY (num_adherent) REFERENCES Adherent(num),
FOREIGN KEY (code_livre) REFERENCES Livre(code)
);
Quand la clef primaire est formée de deux attributs, on l'écrit PRIMARY KEY (a, b). Le SGBD refuse alors toute insertion qui ferait doublon sur le couple, ou qui référencerait une clef inexistante : c'est la contrainte d'intégrité référentielle.
Voici une table unique Commande(num, client, adresse_client, produit, prix) : (1, "Durand", "12 rue Verte, Rennes", "stylo", 2,00) (2, "Durand", "12 rue Verte, Rennes",…
Voici une table unique Commande(num, client, adresse_client, produit, prix) :
(1, "Durand", "12 rue Verte, Rennes", "stylo", 2,00)
(2, "Durand", "12 rue Verte, Rennes", "cahier", 3,50)
(3, "Morel", "5 av. Foch, Brest", "stylo", 2,00)
- a) Repérer la redondance présente dans cette table.
- b) Décrire une anomalie de mise à jour, une anomalie d'insertion et une anomalie de suppression.
- c) Proposer un schéma à trois relations, avec clefs primaires et étrangères, qui supprime ces anomalies.
On considère la relation Inscription(num_etudiant, nom_etudiant, code_cours, intitule_cours, enseignant), avec la clef primaire (num_etudiant, code_cours). Un cours a un…
On considère la relation Inscription(num_etudiant, nom_etudiant, code_cours, intitule_cours, enseignant), avec la clef primaire (num_etudiant, code_cours). Un cours a un seul intitulé et un seul enseignant.
- a) Montrer que cette relation présente des redondances et des anomalies d'insertion, de suppression et de mise à jour.
- b) Proposer une décomposition en relations sans redondance, en précisant clefs primaires et étrangères.
- c) Écrire en SQL les instructions
CREATE TABLEcorrespondantes.
- d) Écrire la requête qui reconstitue la liste (nom d'étudiant, intitulé du cours, enseignant).
Retour à notre médiathèque : quand Léa déménage, il suffit maintenant de modifier une seule ligne de Adherent, et tous ses prêts restent cohérents.
L'essentiel
-
Une base relationnelle est un ensemble de relations (tables) ; leurs colonnes sont les attributs, chacun avec son domaine.
-
La clef primaire identifie chaque enregistrement ; une clef étrangère référence la clef primaire d'une autre table et garantit la cohérence.
-
Requête de sélection :
SELECT … FROM … WHERE … ORDER BY …;DISTINCTsupprime les doublons. -
Mise à jour :
INSERT INTO,UPDATE … SET … WHERE,DELETE FROM … WHERE(ne jamais oublier leWHERE). -
Agrégation :
COUNT,SUM,AVG,MIN,MAX; avecGROUP BY(hors programme) on calcule par groupe, etHAVINGfiltre les groupes. -
Jointure :
JOIN … ON clef_étrangère = clef_primaire. -
Une table qui répète des informations provoque des anomalies de mise à jour, d'insertion et de suppression : on décompose en plusieurs relations reliées par des clefs.