S02 — Bases de données
Modèle relationnel, SQL, jointures, normalisation
🎯 Introduction
Une base de données relationnelle organise les données en tables (relations) composées de lignes (tuples) et de colonnes (attributs). SQL est le langage de requête standard.
✅ Ce qu'il faut savoir
- Modèle relationnel : table, attribut, tuple, schéma
- Clé primaire (PK), clé étrangère (FK), contrainte d'intégrité référentielle
- SELECT, FROM, WHERE, ORDER BY, LIMIT
- Fonctions d'agrégat : COUNT, SUM, AVG, MIN, MAX avec GROUP BY et HAVING
- Jointures : JOIN (INNER), LEFT JOIN
- INSERT, UPDATE, DELETE
📐 Modèle relationnel
Exemple : une base de données de bibliothèque.
-- Schéma relationnel
CREATE TABLE Auteur (
id_auteur INTEGER PRIMARY KEY,
nom TEXT NOT NULL,
nationalite TEXT
);
CREATE TABLE Livre (
isbn TEXT PRIMARY KEY,
titre TEXT NOT NULL,
annee INTEGER,
id_auteur INTEGER REFERENCES Auteur(id_auteur)
ON DELETE CASCADE
);
| Terme | Définition |
|---|---|
| Clé primaire (PK) | Attribut(s) qui identifient uniquement chaque ligne |
| Clé étrangère (FK) | Attribut qui référence la clé primaire d'une autre table |
| Cardinalité | Nombre de lignes satisfaisant une condition (lié à COUNT) |
| Domaine | Ensemble des valeurs possibles d'un attribut |
| Intégrité référentielle | Chaque FK doit référencer une PK existante |
📝 SQL — Requêtes de base
-- Sélectionner toutes les colonnes
SELECT * FROM Livre;
-- Sélection avec condition
SELECT titre, annee
FROM Livre
WHERE annee > 2000
ORDER BY annee DESC;
-- Insérer des données
INSERT INTO Auteur (id_auteur, nom, nationalite)
VALUES (1, 'Camus', 'Française');
-- Modifier des données
UPDATE Livre SET annee = 1942
WHERE isbn = '978-X';
-- Supprimer des lignes
DELETE FROM Auteur
WHERE id_auteur = 5;
🔗 Jointures
Principe de la jointure
Une jointure combine les lignes de deux tables selon une condition de correspondance. Le plus souvent : table1.fk = table2.pk.
-- INNER JOIN : seulement les lignes ayant une correspondance
SELECT Livre.titre, Auteur.nom
FROM Livre
JOIN Auteur ON Livre.id_auteur = Auteur.id_auteur;
-- LEFT JOIN : toutes les lignes de gauche + correspondances (NULL si absent)
SELECT Auteur.nom, Livre.titre
FROM Auteur
LEFT JOIN Livre ON Auteur.id_auteur = Livre.id_auteur;
-- → inclut les auteurs qui n'ont pas de livre (titre = NULL)
-- Jointure de 3 tables
SELECT E.nom, C.nom_cours, N.note
FROM Etudiant E
JOIN Note N ON E.id = N.id_etudiant
JOIN Cours C ON N.id_cours = C.id
WHERE N.note >= 10;
📊 Fonctions d'agrégat
-- COUNT, SUM, AVG, MIN, MAX
SELECT COUNT(*) AS nb_livres -- nombre total
FROM Livre;
-- GROUP BY : grouper par auteur
SELECT id_auteur, COUNT(*) AS nb_livres
FROM Livre
GROUP BY id_auteur;
-- HAVING : filtrer les groupes (après GROUP BY)
SELECT id_auteur, COUNT(*) AS nb
FROM Livre
GROUP BY id_auteur
HAVING COUNT(*) >= 3; -- auteurs avec 3+ livres
-- Requête combinée avec jointure
SELECT Auteur.nom, AVG(Note.note) AS moyenne
FROM Auteur
JOIN Livre ON Auteur.id = Livre.id_auteur
GROUP BY Auteur.nom
HAVING AVG(Note.note) > 4.0
ORDER BY moyenne DESC;
WHERE vs HAVING
WHERE filtre les lignes avant le GROUP BY. HAVING filtre les groupes après le GROUP BY. On ne peut pas utiliser une fonction agrégat dans le WHERE !
❌ WHERE COUNT(*) > 3 → erreur | ✅ HAVING COUNT(*) > 3
🔒 Contraintes et normalisation
| Contrainte | Effet |
|---|---|
| NOT NULL | La valeur ne peut pas être NULL |
| UNIQUE | Chaque valeur doit être unique dans la colonne |
| PRIMARY KEY | NOT NULL + UNIQUE — identifiant unique |
| FOREIGN KEY | Référence à une PK d'une autre table |
| CHECK | Vérifie une condition booléenne |
Propriétés ACID
Atomicité : tout ou rien | Cohérence : intégrité préservée | Isolation : transactions indépendantes | Durabilité : données persistées
Pièges SQL au bac
COUNT(*)compte toutes les lignes,COUNT(col)ignore les NULL- Dans un SELECT avec GROUP BY, on ne peut mettre que des colonnes du GROUP BY ou des fonctions d'agrégat
- La jointure INNER JOIN exclut les lignes sans correspondance (différent de LEFT JOIN)
- SQL n'est pas sensible à la casse pour les mots clés (
SELECT = select), mais peut l'être pour les données
🏋️ Exercices
Table Eleve(id, nom, classe, note). Écrire une requête SQL pour obtenir les noms des élèves de la classe 'TG1' ayant une note supérieure à 15, triés par note décroissante.
✅ Correction
SELECT nom
FROM Eleve
WHERE classe = 'TG1' AND note > 15
ORDER BY note DESC;
Tables : Client(id_client, nom, ville) et Commande(id_cmd, id_client, montant, date).
Trouver le nom et le montant total des commandes pour les clients de Paris ayant commandé pour plus de 500€ au total.
✅ Correction
SELECT C.nom, SUM(Cmd.montant) AS total
FROM Client C
JOIN Commande Cmd ON C.id_client = Cmd.id_client
WHERE C.ville = 'Paris'
GROUP BY C.nom
HAVING SUM(Cmd.montant) > 500;
On filtre d'abord les clients de Paris (WHERE), puis on groupe et on filtre les groupes (HAVING).
📌 Fiche synthèse
STRUCTURE SQL
- SELECT ... FROM ...
- WHERE (filtre lignes)
- GROUP BY + HAVING
- ORDER BY ... ASC/DESC
JOINTURES
- JOIN = INNER JOIN (intersection)
- LEFT JOIN (tout à gauche)
- ON table1.fk = table2.pk
- 3 tables = 2 JOIN
AGRÉGATS
- COUNT(*) / COUNT(col)
- SUM, AVG, MIN, MAX
- WHERE ≠ HAVING
- NULL ignoré par AVG, SUM
🧠 QCM
Choisissez le nombre de questions et le niveau, puis lancez.