Les requêtes SQL

Objectifs Pédagogiques
  • 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, UPDATE et DELETE.
  • 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.

Définition
SQL (Structured Query Language) est un langage déclaratif utilisé pour interagir avec des bases de données relationnelles. Il permet de définir des structures, de manipuler des données, et d'interroger des informations rapidement et efficacement.

SQL est omniprésent dans les systèmes informatiques modernes. Il permet à la fois :

Pourquoi le SQL est-il toujours utilisé aujourd'hui ?

Exemples d'application
  • 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.
À retenir
SQL est un outil essentiel pour manipuler et exploiter efficacement des données relationnelles. Il est utilisé dans tous les secteurs d'activité, quel que soit le volume ou le type d'information à gérer.

Types de données courants

Type SQLDescription
INT, BIGINTNombres entiers (positifs ou négatifs)
SMALLINT, TINYINTEntiers 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, REALNombres 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
TEXTTexte long (commentaires, descriptions...)
DATEDate au format AAAA-MM-JJ
TIME, DATETIMEHeure seule ou date avec heure
BOOLEANValeur logique : TRUE ou FALSE
ENUM(...)Valeur choisie parmi une liste définie (ex : 'Homme', 'Femme')
BLOBDonnées binaires (images, fichiers, sons...)
Exemples de déclarations
  • 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 vs VARCHAR - quand choisir lequel ?
Utilisez 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égorieSignificationExemples
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
Exemples par usage
  • 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).
À retenir
Les commandes DML et DQL sont les plus courantes pour interagir avec les données au quotidien. Les commandes DDL et DCL sont essentielles pour la structure et la sécurité de la base.

Structure d'une base de données

Création d'une base de données

CREATE DATABASE Ecole;
USE Ecole;
Explication
La commande 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
);
Explication des contraintes
  • PRIMARY KEY : identifie chaque ligne de façon unique.
  • AUTO_INCREMENT : la valeur de idEtudiant est 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 pour actif, il vaut TRUE par défaut.
Ce que ça donne dans la table

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
);
Contraintes supplémentaires
  • 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.
À retenir
Bien définir ses contraintes dès la création des tables permet de garantir la cohérence et la qualité des données dans la base. Une contrainte rejetée au niveau de la base vaut mieux qu'une erreur découverte dans l'application.

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;
À retenir
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');
Explication
On insère une ligne dans la table 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);
À retenir
Il est toujours préférable de préciser les colonnes dans l'ordre d'insertion. Cela rend le code plus lisible, robuste et évite des erreurs en cas de changement dans la structure de la table.

Lecture des données : SELECT

SELECT nom, prenom
FROM Etudiant
WHERE dateNaissance > '2001-01-01'
ORDER BY nom ASC;
Explication
La commande 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érateurDescriptionExemple
=, !=, <, >Comparaison classiqueWHERE note > 10
BETWEEN ... AND ...Dans un intervalle (bornes incluses)WHERE note BETWEEN 10 AND 15
IN (...)Parmi une liste de valeursWHERE ville IN ('Lyon', 'Paris')
LIKECorrespondance avec un motifWHERE nom LIKE 'Du%'
IS NULL / IS NOT NULLValeur absente ou présenteWHERE 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;
Le caractère joker % 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.

Bonnes pratiques SELECT
  • Évitez SELECT * dans les applications : préférez lister les colonnes utiles.
  • Utilisez WHERE pour limiter le volume de données retourné.
  • Triez avec ORDER BY pour faciliter la lecture des résultats.
  • Utilisez LIMIT pour ne pas surcharger votre application lors des tests.

Mise à jour : UPDATE

UPDATE Etudiant
SET nom = 'Dupond', email = 'dupond@ecole.fr'
WHERE idEtudiant = 2;
Explication
On modifie le nom et l'email de l'étudiant dont l'idEtudiant est 2. On peut modifier plusieurs colonnes en les séparant par des virgules dans SET.
À retenir - Règle d'or du UPDATE
Toujours utiliser 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;
Explication
Supprime uniquement l'étudiant dont l'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 vs TRUNCATE
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 :

idEtudiantnomprenom
1MartinAlice
2DurandLucas
3LeroyEmma

Inscription (idCours = 10 = "Maths", 20 = "SQL")

idEtudiantidCours
110
120
210

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 :

nomprenomidCours
MartinAlice10
MartinAlice20
DurandLucas10
Jointure interne
Une 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 :

nomprenomidCours
MartinAlice10
MartinAlice20
DurandLucas10
LeroyEmmaNULL
Jointure externe gauche
Une 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 jointureRésultat attendu
INNER JOINCorrespondances exactes dans toutes les tables
LEFT JOINToutes les lignes de gauche, même sans correspondance (droite = NULL)
RIGHT JOINToutes les lignes de droite, même sans correspondance (gauche = NULL)
FULL JOINToutes les lignes des deux tables (non supporté nativement par MySQL)
À retenir
  • Utilisez INNER JOIN quand vous ne voulez que les données qui ont une correspondance dans toutes les tables.
  • Utilisez LEFT JOIN quand vous voulez garder tous les enregistrements de la table principale, même sans correspondance.
  • RIGHT JOIN est rarement utilisé : on préfère inverser l'ordre des tables et utiliser LEFT 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

FonctionRôleExemple
COUNT()Compte le nombre de lignesCOUNT(*), COUNT(idEtudiant)
SUM()Somme les valeursSUM(montant)
AVG()Calcule la moyenneAVG(note)
MAX()Renvoie la valeur maximaleMAX(note)
MIN()Renvoie la valeur minimaleMIN(note)
COUNT(*) vs COUNT(colonne)
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 vs HAVING
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 :

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écutionClauseRôle
1FROM + JOINCharge les tables et les assemble
2WHEREFiltre les lignes
3GROUP BYRegroupe les lignes restantes
4HAVINGFiltre les groupes
5SELECTSélectionne les colonnes (et applique les agrégats)
6DISTINCTSupprime les doublons
7ORDER BYTrie les résultats
8LIMITLimite le nombre de lignes retournées
Pourquoi cet ordre est important
Cela explique pourquoi on ne peut pas utiliser un alias défini dans 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
);
Explication
  • 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.
Ce que garantit l'intégrité référentielle
-- ✅ 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
À retenir
Les clés étrangères garantissent l'intégrité référentielle : on ne peut pas créer de liens vers des données inexistantes.
Choisissez entre ON DELETE CASCADE (suppression en cascade) et ON DELETE RESTRICT (blocage) selon le comportement souhaité.

Ressources complémentaires