4-02. Introduction au langage SQL
Ce chapitre a pour but de vous présenter les commandes de base du langage MySQL (Search Query Language). Les langages SQL sont spécialisés dans les opérations sur les bases de données. Ils sont composés de quelques mots-clé et de quelques fonctions.
Besoin de précision sur une commande ? Cherchez-la sur w3schools.com
Créer une table
- Identifier les composants d’une requête.
Au départ, une base de données est vide. Il faut commencer par la peupler avec des tables (ou relations) – qui seront elles-mêmes vides au départ.
On va reprendre le même thème que l’activité du chapitre précédent. Ça m’évitera de vous présenter une nouvelle situation ! 🤓 Notre base de données servira à gérer une ensemble de livres destinés à être emprunter.
Suivez la progression pas-à-pas en insérant les instructions données dans la console SQL en ligne sur ce site.
🖐️ Aucune sauvegarde n’est possible. 😅 Si vous le souhaitez, vous pouvez aussi installer MySQL sur votre ordinateur personnel… mais c’est assez long, alors vous le ferez chez vous.
Table des auteurs
CREATE TABLE authors (
id INT AUTO_INCREMENT PRIMARY KEY,
lastname VARCHAR(100) NOT NULL, -- string max 100 caractères, valeur obligatoire
firstname VARCHAR(100), -- string max 100 caractères, valeur non obligatoire
country VARCHAR(50) NOT NULL
) ENGINE=InnoDB;
L’extrait de code ci-dessus est assez parlant. On y voit les mots-clés CREATE TABLE, avec les attributs de la relation.
Remarquez qu’un certain nombre de précisions sont associées à ces attributs, permettant de définir la clé primaire (obligatoire) et le domaine de l’attribut.
Une fois ce code exécuté, votre base de données comporte une nouvelle table (vide) avec les attributs mentionnés. Patientez un peu avant de la remplir, on le fera dans le paragraphe suivant.
L’instruction ENGINE=InnoDB est optionnelle. Tout dépend de la configuration du SGBD. Le moteur InnoDB permet de d’empêcher la création d’entrée avec des clés secondaires incohérentes. La plupart du temps, les SGBD sont configurés pour utiliser ce moteur par défaut.
Table des livres
Allez hop ! Voici le code :
CREATE TABLE books (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
date INT CHECK (date IS NULL OR ( date >= 1453 AND date <= 2050 )),
id_author INT NOT NULL,
FOREIGN KEY (id_author) REFERENCES authors(id)
) ENGINE=InnoDB;
Deux nouveautés dans cette table : d’une part la fonction CHECK qui va vérifier la cohérence de la date (l’absence de date est autorisée), et d’autre part la déclaration d’une clé étrangère (FOREIGN KEY).
Table des utilisateurs
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
class VARCHAR(50),
card VARCHAR(20) UNIQUE NOT NULL
) ENGINE=InnoDB;
Ici, encore une (petite nouveauté) : on impose que l’attribut card soit unique, c’est-à-dire que deux entrées dans la table ne peuvent pas avoir le même numéro de carte. Et ce numéro de carte est obligatoire (NOT NULL). Du coup on aurait peut s’en servir comme clé primaire (unique et obligatoire). Mais bon, on reste sur l’attribut "id", qui joue ce rôle – ça correspond plus à la pratique réelle.
Table des emprunts
CREATE TABLE loans (
id_book INT NOT NULL,
id_user INT NOT NULL,
date DATE NOT NULL,
PRIMARY KEY (id_book, id_user),
FOREIGN KEY (id_book) REFERENCES books(id),
FOREIGN KEY (id_user) REFERENCES users(id)
) ENGINE=InnoDB;
Dernière table, dernière nouveauté. La clé primaire est ici le tuple ("id_book", "id_user"). En effet, une même personne ne peut emprunter le même livre simultanément qu’une seule fois. Ça suppose d’ailleurs qu’une fois le livre rendu, on efface l’entrée correspondante dans la table. Ce n’est pas forcément la meilleure solution, car du coup on ne peut pas garder d’historique des emprunts. Mais là encore, c’est pour l’exemple et pour respecter l’activité précédente.
Maintenant que vous avez créé ces quatre tables, vous avez la structure de votre base de données… Mais aucune donnée. 😏 C’est donc le moment de…
Lorsqu’on travaille sur des bases de données, on utilise souvent une application rajoutant une interface graphique, telle que PHPMyAdmin, Adminer ou encore faite sur mesure.
Ces application permettent de réaliser des opérations sans utiliser de commande SQL directement. Elles sont donc plus simples à utiliser et moins intimidantes que les lignes de commande.
Mais pour s’en servir efficacement, il faut connaître le langage SQL afin de comprendre les opérations réalisées et leur signification.
Créer des entrées
- Construire des requêtes avec INSERT.
Pour créer une entrée, la commande est INSERT INTO .... C’est assez simple, il vous suffit de regarder la structure des différentes commandes ci-dessous.
Remarquez bien qu’après chaque commande, un point-virgule est nécessaire. En effet, MySQL, comme beaucoup d’autres langages (mais pas Python), ne tient pas compte des retours à la ligne. Vous en mettez où vous voulez pour rendre votre code plus lisible. Du coup, il faut que le langage comprenne où s’arrête une commande et où commence la suivante. Le point-virgule est là pour ça !
INSERT INTO authors (lastname, firstname, country) VALUES("Orwell", "George", "Grande Bretagne");
INSERT INTO books (title, date, id_author) VALUES ("Animal Farm", 1945, 1);
-- Insertion devant causer des erreurs
INSERT INTO books (title, date, id_author) VALUES ("Animal Farm 2", 1945, 3);
INSERT INTO books (title, date, id_author) VALUES ("Animal Farm 3", 19450, 1);
-- Insertion de plusieurs entrées
INSERT INTO `authors` (`lastname`, `firstname`, `country`) VALUES
('Salinger', 'J.D.', 'États-Unis'),
('Lee', 'Harper', 'États-Unis'),
('Golding', 'William', 'Grande Bretagne'),
('Green', 'John', 'États-Unis'),
('Austen', 'Jane', 'Grande Bretagne'),
('Huxley', 'Aldous', 'Grande Bretagne'),
('Fitzgerald', 'F. Scott', 'États-Unis'),
('Wilde', 'Oscar', 'Irlande'),
('Haddon', 'Mark', 'Grande Bretagne'),
('Steinbeck', 'John', 'États-Unis'),
('Simmons', 'Dan', 'États-Unis'),
('Tolkien', 'J.R.R.', 'Grande Bretagne');
À ce stade, vous pouvez télécharger le fichier nsi-books-v01.sql et l’importer dans votre base (repartez de zéro en rafraîchissant la page).
Pour les curieux, si vous ouvrez ce fichier avec un éditeur de texte ou de code, vous verrez qu’il s’agit d’un ensemble de commandes SQL qui servent à créer la base de données. C’est ce qu’on appelle un « dump » de la base. Ça permet d’importe et d’exporte des bases de données d’un SGBD à l’autre.
Lire des données
- Construire des requêtes SQL avec SELECT, FROM, WHERE, JOIN.
Lire des données dans une (ou plusieurs) tables est l’opération la plus courante. La commande se construit avec SELECT ... FROM ....
La quantité de données pouvant être très importante, on y ajoute souvent les clauses WHERE et ORDER BY. Regardez les quelques exemples ci-dessous, ils parlent d’eux-même.
Provenant d’une table unique
SELECT * FROM books; -- sélectionner tous les champs
SELECT title, date FROM books; -- sélectionner certains champs
-- avec WHERE → ajout d’une condition
SELECT * FROM books WHERE date > 1990;
SELECT title, date FROM books WHERE date >= 1900 AND date <= 1950;
-- avec ORDER BY (ordre ASC ou DESC)
SELECT title, date FROM books ORDER BY date; -- par défaut ordre croissant (ASC)
SELECT lastname, firstname FROM authors ORDER BY lastname;
SELECT title, date FROM books ORDER BY date DESC;
SELECT title, date FROM books WHERE date > 1900 ORDER BY date DESC;
Écrire la requête permettant d’obtenir la liste des auteurs britanniques par ordre alphabétique.
Fonctions
Le langage MySQL comporte quelques fonctions natives que l’on peut utiliser dans une requête. En voici quelques exemples :
-- compter des entrées
SELECT COUNT(*) AS nb_livres FROM books;
SELECT COUNT(firstname) FROM authors; -- auteurs avec prénom
SELECT COUNT(*) FROM authors WHERE firstname IS NULL; -- auteur sans prénom
-- minimum et maximum
SELECT MIN(date) AS plus_ancien FROM books;
SELECT MAX(date) AS plus_recent FROM books;
GROUP BY
Un peu plus subtil, le mot-clé GROUP BY. Ce mot-clé regroupe les entrées qui ont les mêmes valeurs en une unique ligne.
Utilisez la commande ci-dessous et essayez de comprendre le résultat affiché.
SELECT * FROM authors GROUP BY country
Le résultat obtenu comporte seulement trois auteurs, des trois pays différents présents dans le champ country de la table authors. Ces trois auteurs sont le premier auteur dont le champ country est "Grande Bretagne", puis le premier auteur dont le champ country est "États-Unis", etc.
En l’état, cette commande n’a bien sûr aucun intérêt, car les noms des auteurs sont tous différents. Mais regardez son utilisation ci-dessous :
SELECT country, COUNT(*) AS nb_auteurs FROM authors GROUP BY country;
Cette commande permet d’obtenir le nombre d’auteurs des différents pays.
Autres mots-clés : LIMIT, LIKE, DISTINCT
Le mot-clé LIMIT limite le nombre de résultats affichés. Il peut être utile dans le cas où la recherche est susceptible de renvoyer un grand nombre d’entrée.
SELECT * FROM books WHERE date >= 1950 ORDER BY date LIMIT 4;
Le mot-clé LIKE permet de recherche des valeurs d’attributs de type texte avec une correspondance partielle.
SELECT * FROM books WHERE date >= 1950 AND title LIKE "%ring%";
La commande précédente va retourner tous les livres dont le titre contient ring, même s’il y a des caractères avant et après.
Le mot-clé DISTINCT, utilisé juste après SELECT, permet d’obtenir uniquement les valeurs distinctes.
SELECT DISTINCT country FROM authors;
users.
Provenant de plusieurs tables
JOIN
Il est souvent nécessaire de chercher des données provenant de plusieurs tables différentes. Par exemple, on peut vouloir avoir la liste des livres avec le nom et le prénom de l’auteur, plutôt que son id. Pour cela, on va joindre deux tables en précisant les attributs de chaque table qui permettent de faire cette jointure.
SELECT books.title, books.date, authors.lastname, authors.firstname
FROM books
JOIN authors ON books.id_author = authors.id;
Cette requête permet de chercher des valeurs sur deux tables différentes : books et authors. Remarquez que, du coup, lorsqu’on précise les attributs à sélectionner, on doit également préciser sur quelle table on doit les chercher.
La commande JOIN permet de préciser quelle table on joint à la table principale (books), mais aussi et surtout comment trouver la correspondance entre les entrées des différentes tables.
Écrire la requête permettant d’obtenir les auteurs des livres empruntés associés au nom des élèves qui ont fait l’emprunt.
Il est possible de joindre plus de deux tables.
SELECT books.title, users.name, loans.date
FROM loans
JOIN books ON loans.id_book = books.id
JOIN users ON loans.id_user = users.id
ORDER BY loans.date;
HAVING
WHERE et HAVING servent tous deux à filtrer les éléments d’une requête. La principale différence entre ces deux mots-clés est que WHERE filtre les lignes individuelles avant tout regroupement, alors que HAVING filtre les groupes après l'application de la clause GROUP BY.
-- Cette requête ne fonctionnera pas comme souhaité
SELECT authors.country, COUNT(*) AS nb_auteurs
FROM authors
WHERE COUNT(*) > 2
GROUP BY authors.country;
-- Version correcte avec HAVING
SELECT authors.country, COUNT(*) AS nb_auteurs
FROM authors
GROUP BY authors.country
HAVING COUNT(*) > 2;
La première requête génèrerait une erreur car les fonctions d’agrégation comme COUNT() ne peuvent pas être utilisées dans la clause WHERE. En effet, WHERE s’applique aux lignes individuelles avant le regroupement, alors que COUNT() opère sur des groupes.
Quelques requêtes avec SELECT
1. Analyser les requêtes ci-dessous pour prévoir ce qu’elles font.
-- Requête n°1
SELECT users.name, COUNT(*) AS nb_emprunts
FROM loans
JOIN users ON loans.id_user = users.id
GROUP BY users.id
ORDER BY nombre_emprunts DESC;
-- Requête n°2
SELECT authors.lastname, authors.firstname, COUNT(*) AS nb_livres
FROM books
JOIN authors ON books.id_author = authors.id
GROUP BY authors.id
ORDER BY nombre_livres DESC;
-- Requête n°3
SELECT books.id, books.title
FROM books
WHERE books.id NOT IN (SELECT id_book FROM loans);
2. Une requête facile : Lister tous les livres publiés avant 1900
3. Filtrage multiple : Trouver tous les livres des auteurs américains
4. Analyse de données : Combien d'élèves de la classe "1e 2" ont emprunté des livres ? Vous utiliserez le mot clé DISTINCT pour éviter de compter deux fois un même élève ayant emprunter deux livres.
5. Recherche : Trouver tous les livres dont le titre contient le mot "the". Documentez-vous sur le mot-clé LIKE.
Correction
3. Tous les livres des auteurs américains
SELECT books.id, books.title
FROM books
JOIN authors ON books.id_author = authors.id
WHERE authors.country = "États-Unis"
4. Nombre d’élèves de 1e 2 ayant emprunté des livres
SELECT COUNT(DISTINCT users.id) AS nb_eleves
FROM users
JOIN loans ON users.id = loans.id_user
WHERE users.class = "1e 2"
5. Auteur dont les livres sont les plus empruntés
SELECT id, title
FROM books
WHERE title LIKE "%the%"
Modifier des entrées
- Construire des requêtes avec UPDATE.
La commande pour modifier une (ou plusieurs) entrée(s) est UPDATE. Attention, cette commande modifie le contenu de votre base de données. Une mauvaise manip peut potentiellement être catastrophique en situation réelle ! 😅 Il n’y a pas de
UPDATE users SET class="1e 1", card="E074" WHERE id = 1;
Je pense que cette commande est suffisamment parlante pour se passer de commentaires.
Si vous oubliez le WHERE id = 1, la modification sera faite sur TOUTES les entrées de la table. Et là, vous êtes dans la m…ésaventure ! Surtout si vous n’aviez pas fait de sauvegarde de votre base de données au préalable.
Modifier des données
1. Emma change de classe. Elle passe en 1e 2. Proposer une commande permettant de mettre à jour cette information dans la base de données.
2. Madame B. décide de changer le nom des classes pour éviter les erreurs. "1e 1" devient "1-1", "1e-2" devient "1-2" et "2nde 1" devient "2-1". Proposer les commandes permettant de faire ces modifications.
Correction
Supprimer des entrées
- Construire des requêtes avec DELETE.
Voilà une commande très simple, car elle efface l’entrée complète. Il s’agit de DELETE.
DELETE FROM users WHERE class="1e 1"
Là encore, la commande est explicite. Et là encore, si elle est mal formulée, les effets peuvent être dévastateurs… 😅
Supprimer des données
1. Nicolas (id 5), rend tous ses livres. Écrire la commande permettant de supprimer ses emprunts.
2. À la fin de l’années, tous les élèves ayant emprunté des livres les rendent à Madame B. Comment faire pour vider la table loans ?
Correction
Révision & entraînement
Extrait de ADN 2025-1
Cet exercice est extrait du sujet 1 Amérique du Nord 2025 – exercice 3 partie A.
Une association s’occupe d’enfants de 0 à 18 ans. Elle souhaite pouvoir former des groupes d’enfants qui s’entendent durant les activités proposées.
On pourra utiliser les clauses du langage SQL pour :
- construire des requêtes d’interrogation à l’aide de SELECT, FROM, WHERE (avec les opérateurs logiques AND et OR), JOIN ... ON ;
- construire des requêtes d’insertion et de mise à jour à l’aide de UPDATE, INSERT, DELETE ;
- affiner les recherches à l’aide de DISTINCT, ORDER BY.
On considère une base de données composée des trois tables suivantes :
Table parent :
nomest le nom de famille du parent ;telest le numéro de téléphone du parent ;codepest le code postal de la ville où réside le parent.
Table enfant :
idest l’identifiant de l’enfant pour l’association ;prenomest le prénom de l’enfant ;num_parentest le téléphone du parent référent ;- annee est l’année de naissance de l’enfant.
Table mesentente :
enfant1est l’identifiant d’un premier enfant ;enfant2est l’identifiant d’un second enfant.
Ainsi, on considère que deux enfants qui se trouvent sur la même ligne dans la table mesentente ne peuvent pas effectuer de sortie ensemble.
Le schéma relationnel de la BDD est donné en figure 1, avec la convention que les attributs formant une clef primaire sont soulignés tandis que ceux d’une clef étrangère sont précédés d’un croisillon (symbole #) avec une flèche vers l’attribut référencé.