Les requêtes SQL
- Comprendre le rôle du langage SQL dans la gestion des bases de données relationnelles.
- Créer une base de données et des tables avec des contraintes simples.
- Manipuler les données avec les instructions
SELECT,INSERT,UPDATEetDELETE. - Interroger les données avec des filtres, des tris, des jointures simples et des fonctions d'agrégation.
À quoi sert SQL ?
Dans les chapitres précédents, vous avez appris à modéliser une base de données (MCD, MLD) et à raisonner sur les données avec l'algèbre relationnelle. SQL est la traduction concrète de tout cela : c'est le langage que vous tapez pour interroger une vraie base de données.
SQL est omniprésent dans les systèmes informatiques modernes. Il permet à la fois :
- De créer et structurer une base de données (
CREATE,ALTER,DROP) ; - D'ajouter, modifier ou supprimer des données (
INSERT,UPDATE,DELETE) ; - D'interroger et exploiter les données (
SELECT,JOIN,GROUP BY, etc.) ; - De contrôler les accès et la sécurité (
GRANT,REVOKE) ; - De générer des statistiques simples (moyennes, totaux, comptages).
Pourquoi le SQL est-il toujours utilisé aujourd'hui ?
- Standardisé : SQL est un langage reconnu par tous les grands systèmes de gestion de bases de données (MySQL, PostgreSQL, Oracle, SQL Server…).
- Lisible : sa syntaxe proche du langage naturel le rend facilement compréhensible.
- Puissant : il permet de traiter efficacement de très grandes quantités de données.
- Transverse : il est utilisé dans presque tous les métiers liés à la donnée.
- Informatique : authentification, gestion des comptes, suivi des activités utilisateur.
- BTP : planification des interventions, suivi des livraisons, gestion des équipements.
- Énergie : gestion des capteurs, alertes sur la consommation, historique des relevés.
- Transport : géolocalisation des véhicules, affectation des tournées, suivi des colis.
- Industrie : traçabilité des produits, contrôle qualité, gestion de la maintenance.
Types de données courants
| Type SQL | Description |
|---|---|
INT, BIGINT | Nombres entiers (positifs ou négatifs) |
SMALLINT, TINYINT | Entiers de plus petite taille (moins de mémoire utilisée) |
DECIMAL(p,s) | Nombres décimaux précis avec p chiffres au total et s après la virgule |
FLOAT, REAL | Nombres décimaux à virgule flottante (moins précis, plus légers) |
CHAR(n) | Texte fixe de longueur n (utile pour des codes, comme un code postal) |
VARCHAR(n) | Texte variable jusqu'à n caractères |
TEXT | Texte long (commentaires, descriptions...) |
DATE | Date au format AAAA-MM-JJ |
TIME, DATETIME | Heure seule ou date avec heure |
BOOLEAN | Valeur logique : TRUE ou FALSE |
ENUM(...) | Valeur choisie parmi une liste définie (ex : 'Homme', 'Femme') |
BLOB | Données binaires (images, fichiers, sons...) |
nom VARCHAR(50): chaîne de texte pouvant aller jusqu'à 50 caractères.montant DECIMAL(8,2): valeur numérique avec 6 chiffres avant la virgule et 2 après (ex : 123456.78).sexe ENUM('Homme', 'Femme', 'Autre'): contraint la valeur à une liste prédéfinie.codePostal CHAR(5): champ texte fixe pour un code à 5 chiffres.photo BLOB: stocke une image en base de données (rarement conseillé).
CHAR(n) quand la valeur a toujours exactement la même taille (code postal, numéro INSEE, identifiant fixe).Utilisez
VARCHAR(n) pour les textes de longueur variable (noms, adresses, titres).CHAR est légèrement plus rapide ; VARCHAR économise de l'espace disque.Familles de commandes SQL
Le langage SQL est divisé en plusieurs familles de commandes, selon leur rôle dans la gestion d'une base de données relationnelle.
| Catégorie | Signification | Exemples |
|---|---|---|
| DDL (Data Definition Language) | Définir ou modifier la structure des objets (tables, vues, clés). | CREATE, ALTER, DROP |
| DML (Data Manipulation Language) | Ajouter, modifier ou supprimer des données. | INSERT, UPDATE, DELETE |
| DQL (Data Query Language) | Interroger les données pour les lire ou les analyser. | SELECT |
| DCL (Data Control Language) | Gérer les permissions et la sécurité d'accès. | GRANT, REVOKE |
| TCL (Transaction Control Language) | Contrôler les transactions (groupes d'opérations atomiques). | COMMIT, ROLLBACK |
- DDL : Créer une nouvelle table dans la base.
- DML : Ajouter un étudiant ou modifier son prénom.
- DQL : Rechercher tous les étudiants nés après 2001.
- DCL : Donner à un utilisateur le droit de modifier la table
Etudiant. - TCL : Annuler une série d'insertions en cas d'erreur (
ROLLBACK).
Structure d'une base de données
Création d'une base de données
CREATE DATABASE Ecole;
USE Ecole;
CREATE DATABASE crée une base nommée Ecole. La commande USE permet de travailler à l'intérieur de cette base. Toutes les commandes suivantes s'appliqueront à cette base tant qu'on ne change pas de contexte.Création d'une table
CREATE TABLE Etudiant (
idEtudiant INT PRIMARY KEY AUTO_INCREMENT,
nom VARCHAR(50) NOT NULL,
prenom VARCHAR(50) NOT NULL,
dateNaissance DATE,
email VARCHAR(100) UNIQUE,
actif BOOLEAN DEFAULT TRUE
);
PRIMARY KEY: identifie chaque ligne de façon unique.AUTO_INCREMENT: la valeur deidEtudiantest générée automatiquement (1, 2, 3…). Plus besoin de la saisir manuellement.NOT NULL: le champ est obligatoire - il ne peut pas être vide.UNIQUE: deux lignes ne peuvent pas avoir la même valeur (ici, deux étudiants ne peuvent pas avoir le même email).DEFAULT TRUE: si on n'indique pas de valeur pouractif, il vautTRUEpar défaut.
Une fois la table créée, vous pourrez y stocker des données comme :
+------------+--------+--------+---------------+---------------------+-------+
| idEtudiant | nom | prenom | dateNaissance | email | actif |
+------------+--------+--------+---------------+---------------------+-------+
| 1 | Martin | Alice | 2001-05-12 | alice@ecole.fr | 1 |
| 2 | Durand | Lucas | 2000-11-03 | lucas@ecole.fr | 1 |
+------------+--------+--------+---------------+---------------------+-------+
idEtudiant a été généré automatiquement grâce à AUTO_INCREMENT.
Autres contraintes utiles
CREATE TABLE Cours (
idCours INT PRIMARY KEY AUTO_INCREMENT,
intitule VARCHAR(100) NOT NULL,
volumeHoraire INT CHECK (volumeHoraire > 0),
coefficient DECIMAL(3,1) DEFAULT 1.0
);
CHECK: impose une condition logique sur la valeur (ici, le volume horaire doit être positif).DEFAULT 1.0: si aucun coefficient n'est précisé à l'insertion, la valeur 1.0 est utilisée automatiquement.
Modifier la structure d'une table : ALTER TABLE
Après la création, il est possible de modifier la structure d'une table sans la supprimer.
-- Ajouter une colonne
ALTER TABLE Etudiant ADD COLUMN telephone VARCHAR(15);
-- Modifier le type d'une colonne
ALTER TABLE Etudiant MODIFY COLUMN telephone VARCHAR(20);
-- Supprimer une colonne
ALTER TABLE Etudiant DROP COLUMN telephone;
-- Renommer une colonne (MySQL 8+)
ALTER TABLE Etudiant RENAME COLUMN actif TO estActif;
ALTER TABLE fait partie du DDL. Utilisez-le quand vous devez faire évoluer le schéma sans perdre les données existantes. En production, ces modifications doivent être planifiées avec soin (risque de perte de données si on supprime une colonne).Manipuler les données avec SQL
Insertion de données : INSERT
INSERT INTO Etudiant (nom, prenom, dateNaissance, email)
VALUES ('Durand', 'Claire', '2001-03-25', 'claire@ecole.fr');
Etudiant. On ne précise pas idEtudiant car il est généré automatiquement par AUTO_INCREMENT. Les colonnes non mentionnées (actif) prendront leur valeur par défaut.Insérer plusieurs lignes à la fois :
INSERT INTO Etudiant (nom, prenom, dateNaissance, email)
VALUES
('Dupont', 'Pierre', '2000-05-12', 'pierre@ecole.fr'),
('Martin', 'Sophie', '2002-07-18', 'sophie@ecole.fr');
Sans nommer les colonnes (déconseillé) :
-- ⚠️ Déconseillé : fragile si la structure de la table change
INSERT INTO Etudiant
VALUES (NULL, 'Lefevre', 'Luc', '2001-11-30', NULL, TRUE);
Lecture des données : SELECT
SELECT nom, prenom
FROM Etudiant
WHERE dateNaissance > '2001-01-01'
ORDER BY nom ASC;
SELECT permet d'afficher les données souhaitées. Ici, on affiche nom et prenom des étudiants nés après le 1er janvier 2001, triés par nom croissant.Opérateurs de filtre courants
| Opérateur | Description | Exemple |
|---|---|---|
=, !=, <, > | Comparaison classique | WHERE note > 10 |
BETWEEN ... AND ... | Dans un intervalle (bornes incluses) | WHERE note BETWEEN 10 AND 15 |
IN (...) | Parmi une liste de valeurs | WHERE ville IN ('Lyon', 'Paris') |
LIKE | Correspondance avec un motif | WHERE nom LIKE 'Du%' |
IS NULL / IS NOT NULL | Valeur absente ou présente | WHERE email IS NOT NULL |
-- Étudiants dont le nom commence par "Du"
SELECT * FROM Etudiant WHERE nom LIKE 'Du%';
-- Étudiants sans email renseigné
SELECT nom, prenom FROM Etudiant WHERE email IS NULL;
-- Notes entre 10 et 15 inclus
SELECT * FROM Inscription WHERE note BETWEEN 10 AND 15;
% dans LIKE% remplace n'importe quelle suite de caractères (y compris vide)._ remplace exactement un caractère.Exemples :
'Du%' → commence par "Du" | '%on' → finit par "on" | 'D_pont' → "Dupont", "Damont", etc.Afficher des valeurs distinctes : DISTINCT
SELECT DISTINCT ville FROM Client;
DISTINCT supprime les doublons dans le résultat : si 50 clients habitent Lyon, "Lyon" n'apparaît qu'une fois.
Limiter le nombre de résultats : LIMIT
SELECT nom, prenom FROM Etudiant ORDER BY nom ASC LIMIT 10;
Retourne uniquement les 10 premiers résultats - utile pour la pagination ou pour tester une requête.
- Évitez
SELECT *dans les applications : préférez lister les colonnes utiles. - Utilisez
WHEREpour limiter le volume de données retourné. - Triez avec
ORDER BYpour faciliter la lecture des résultats. - Utilisez
LIMITpour ne pas surcharger votre application lors des tests.
Mise à jour : UPDATE
UPDATE Etudiant
SET nom = 'Dupond', email = 'dupond@ecole.fr'
WHERE idEtudiant = 2;
idEtudiant est 2. On peut modifier plusieurs colonnes en les séparant par des virgules dans SET.WHERE pour cibler les lignes à modifier. Un UPDATE Etudiant SET nom = 'Dupond' sans WHERE modifie tous les étudiants de la table - erreur irrécupérable sans sauvegarde.Suppression : DELETE
DELETE FROM Etudiant
WHERE idEtudiant = 4;
idEtudiant est 4. Préférez toujours filtrer sur la clé primaire pour cibler exactement une ligne.Supprimer toutes les données de la table (dangereux) :
-- Supprime toutes les lignes une par une (lent, journalisé)
DELETE FROM Etudiant;
-- Vide la table d'un coup et réinitialise l'AUTO_INCREMENT (plus rapide, non journalisé)
TRUNCATE TABLE Etudiant;
DELETE sans WHERE supprime toutes les lignes mais conserve la structure et peut être annulé avec ROLLBACK.TRUNCATE vide la table et remet l'AUTO_INCREMENT à 1 - opération non annulable. À réserver aux environnements de développement.Requêtes avec jointures
Une jointure permet de combiner des données provenant de plusieurs tables. C'est l'opération clé dans une base relationnelle, où les informations sont réparties sur plusieurs tables reliées par des clés.
Données d'exemple
Pour illustrer les jointures, imaginons ces deux tables :
Table Etudiant :
| idEtudiant | nom | prenom |
|---|---|---|
| 1 | Martin | Alice |
| 2 | Durand | Lucas |
| 3 | Leroy | Emma |
Inscription (idCours = 10 = "Maths", 20 = "SQL")
| idEtudiant | idCours |
|---|---|
| 1 | 10 |
| 1 | 20 |
| 2 | 10 |
Emma (id=3) n'a aucune inscription.
Jointure interne (INNER JOIN)
SELECT e.nom, e.prenom, i.idCours
FROM Etudiant e
JOIN Inscription i ON e.idEtudiant = i.idEtudiant;
Résultat :
| nom | prenom | idCours |
|---|---|---|
| Martin | Alice | 10 |
| Martin | Alice | 20 |
| Durand | Lucas | 10 |
JOIN (ou INNER JOIN) ne conserve que les lignes ayant une correspondance dans les deux tables. Emma n'apparaît pas car elle n'a aucune inscription.Jointure externe gauche (LEFT JOIN)
SELECT e.nom, e.prenom, i.idCours
FROM Etudiant e
LEFT JOIN Inscription i ON e.idEtudiant = i.idEtudiant;
Résultat :
| nom | prenom | idCours |
|---|---|---|
| Martin | Alice | 10 |
| Martin | Alice | 20 |
| Durand | Lucas | 10 |
| Leroy | Emma | NULL |
LEFT JOIN conserve toutes les lignes de la table de gauche (Etudiant), même si elles n'ont pas de correspondance à droite. Emma apparaît avec NULL dans idCours.Jointure sur 3 tables
SELECT e.nom, c.intitule
FROM Etudiant e
JOIN Inscription i ON e.idEtudiant = i.idEtudiant
JOIN Cours c ON i.idCours = c.idCours;
On chaîne les jointures pour remonter les données à travers la table de liaison Inscription.
Résumé des types de jointures
| Type de jointure | Résultat attendu |
|---|---|
INNER JOIN | Correspondances exactes dans toutes les tables |
LEFT JOIN | Toutes les lignes de gauche, même sans correspondance (droite = NULL) |
RIGHT JOIN | Toutes les lignes de droite, même sans correspondance (gauche = NULL) |
FULL JOIN | Toutes les lignes des deux tables (non supporté nativement par MySQL) |
- Utilisez
INNER JOINquand vous ne voulez que les données qui ont une correspondance dans toutes les tables. - Utilisez
LEFT JOINquand vous voulez garder tous les enregistrements de la table principale, même sans correspondance. RIGHT JOINest rarement utilisé : on préfère inverser l'ordre des tables et utiliserLEFT JOIN.
Requêtes avec agrégats
Les fonctions d'agrégation permettent de faire des calculs sur plusieurs lignes d'une table. Elles sont très utiles pour obtenir des statistiques ou des résumés de données.
Fonctions d'agrégation disponibles
| Fonction | Rôle | Exemple |
|---|---|---|
COUNT() | Compte le nombre de lignes | COUNT(*), COUNT(idEtudiant) |
SUM() | Somme les valeurs | SUM(montant) |
AVG() | Calcule la moyenne | AVG(note) |
MAX() | Renvoie la valeur maximale | MAX(note) |
MIN() | Renvoie la valeur minimale | MIN(note) |
COUNT(*) compte toutes les lignes, y compris celles avec des NULL.COUNT(colonne) ne compte que les lignes où la colonne n'est pas NULL.Renommer une colonne avec AS
SELECT COUNT(*) AS total_etudiants, AVG(note) AS moyenne_generale
FROM Inscription;
AS donne un alias lisible à la colonne résultante. C'est particulièrement utile avec les agrégats, qui n'ont pas de nom par défaut.
Regrouper des résultats : GROUP BY
SELECT idCours, COUNT(*) AS nb_inscrits, AVG(note) AS moyenne
FROM Inscription
GROUP BY idCours;
Calcule le nombre d'inscrits et la moyenne pour chaque cours.
Filtrer les groupes : HAVING
SELECT idCours, AVG(note) AS moyenne
FROM Inscription
GROUP BY idCours
HAVING AVG(note) > 12;
WHERE filtre les lignes avant le regroupement - il s'applique aux données brutes.HAVING filtre les groupes après le GROUP BY - il s'applique aux résultats agrégés.On ne peut pas écrire
WHERE AVG(note) > 12 : WHERE ne connaît pas encore la moyenne à ce stade.Exemple complet avec jointure + agrégat
SELECT c.intitule, COUNT(*) AS nb_etudiants, AVG(i.note) AS moyenne
FROM Cours c
JOIN Inscription i ON c.idCours = i.idCours
GROUP BY c.intitule
HAVING AVG(i.note) >= 10
ORDER BY moyenne DESC;
Cette requête :
- Affiche chaque cours avec le nombre d'étudiants inscrits et la moyenne des notes,
- Ne garde que les cours avec une moyenne ≥ 10,
- Trie les résultats par moyenne décroissante.
Ordre d'exécution d'une requête SQL
Il est important de comprendre que SQL n'exécute pas les clauses dans l'ordre où on les écrit.
| Ordre d'exécution | Clause | Rôle |
|---|---|---|
| 1 | FROM + JOIN | Charge les tables et les assemble |
| 2 | WHERE | Filtre les lignes |
| 3 | GROUP BY | Regroupe les lignes restantes |
| 4 | HAVING | Filtre les groupes |
| 5 | SELECT | Sélectionne les colonnes (et applique les agrégats) |
| 6 | DISTINCT | Supprime les doublons |
| 7 | ORDER BY | Trie les résultats |
| 8 | LIMIT | Limite le nombre de lignes retournées |
SELECT dans une clause WHERE : WHERE est exécuté avant SELECT, donc l'alias n'existe pas encore.En revanche, on peut utiliser cet alias dans
ORDER BY (qui vient après).Créer une table avec une clé étrangère
CREATE TABLE Inscription (
idEtudiant INT,
idCours INT,
note DECIMAL(4,2),
PRIMARY KEY (idEtudiant, idCours),
FOREIGN KEY (idEtudiant) REFERENCES Etudiant(idEtudiant) ON DELETE CASCADE,
FOREIGN KEY (idCours) REFERENCES Cours(idCours) ON DELETE RESTRICT
);
- Clé primaire composite : le couple
(idEtudiant, idCours)est unique - un étudiant ne peut s'inscrire qu'une seule fois à un même cours. - FOREIGN KEY : crée un lien vers une autre table. Le SGBD vérifie que la valeur existe bien dans la table référencée.
- ON DELETE CASCADE : si un étudiant est supprimé, ses inscriptions sont automatiquement supprimées aussi.
- ON DELETE RESTRICT : si un cours est supprimé mais a des inscrits, la suppression est bloquée. Protection contre les suppressions accidentelles.
-- ✅ Fonctionne si idEtudiant=1 et idCours=10 existent
INSERT INTO Inscription VALUES (1, 10, 14.5);
-- ❌ Erreur : l'étudiant 99 n'existe pas dans la table Etudiant
INSERT INTO Inscription VALUES (99, 10, 12.0);
-- Error: Cannot add or update a child row: a foreign key constraint fails
Choisissez entre
ON DELETE CASCADE (suppression en cascade) et ON DELETE RESTRICT (blocage) selon le comportement souhaité.