Le langage SQL
Pour communiquer avec le SGBD, on utilise des requêtes. Ce sont des demandes que l'on formule au système et auxquelles il fournit une réponse. C'est exactement le même principe qu'avec les requêtes HTTP dans la relation client-serveur
Pour formuler ces requêtes, on utilise le langage SQL. Il s'agit d'un langage déclaratif, et pas d'un langage de programmation. En effet, on demande au SGBD de lire ou d'accéder à une partie de la base, mais c'est lui qui choisit comment il va faire.
Clause SELECT : Les requêtes d'accès en lecture
Commencons par un exemple. Considérons la relation suivante :
| Livres | |||||
|---|---|---|---|---|---|
| ID | Titre | Auteur | Parution | Genre | Stock |
| 101 | Le Petit Prince | Antoine de Saint-Exupéry | 1943 | Roman | 4 |
| 102 | 1984 | George Orwell | 1949 | Science-fiction | 2 |
| 103 | Orgueil et Préjugés | Jane Austen | 1813 | Roman | 3 |
| 104 | Le Seigneur des Anneaux | J.R.R. Tolkien | 1954 | Aventure | 5 |
| 105 | Harry Potter à l'école des sorciers | J.K. Rowling | 1997 | Aventure | 4 |
| 106 | Les Misérables | Victor Hugo | 1862 | Roman | 3 |
| 107 | Le Comte de Monte-Cristo | Alexandre Dumas | 1844 | Aventure | 6 |
| 108 | Bel-Ami | Guy de Maupassant | 1885 | Roman | 4 |
| 109 | Fondation | Isaac Asimov | 1951 | Science-fiction | 7 |
| 110 | Dune | Frank Herbert | 1965 | Science-fiction | 5 |
Supposons que je veuille afficher l'ensemble des titres des livres de la base de données. La requête à écrire sera celle-ci :
SELECT Titre FROM Livres;
Le SGBD renvoie :
Titre ___________________________________ Le Petit Prince 1984 Orgueil et Préjugés Le Seigneur des Anneaux Harry Potter à l'école des sorciers Les Misérables Le Comte de Monte-Cristo Bel-Ami Fondation Dune |
Il est également possible d'ajouter d'autres attributs. Si on veut également afficher l'auteur et l'année de parution, on écrira cette requête :
SELECT Titre, Auteur, Parution FROM Livres;
Titre Auteur Parution ____________________________________________________________________________ Le Petit Prince Antoine de Saint-Exupéry 1943 1984 George Orwell 1949 Orgueil et Préjugés Jane Austen 1813 Le Seigneur des Anneaux J.R.R. Tolkien 1954 Harry Potter à l'école des sorciers J.K. Rowling 1997 Les Misérables Victor Hugo 1862 Le Comte de Monte-Cristo Alexandre Dumas 1844 Bel-Ami Guy de Maupassant 1885 Fondation Isaac Asimov 1951 Dune Frank Herbert 1965 |
Remarque
Enfin, on peut également utiliser le symbole * en tant que "wild card", que l'on pourrait traduire par "joker". Il signifie que l'on souhaite afficher tous les attributs.
SELECT * FROM Livres;
Clause WHERE : Ajout de conditions
Supposons maintenant que je ne veuille pas afficher toute la base, mais seulement une partie, selon des conditions à définir. Par exemple, afficher les titres des oeuvres parues après 1900 :
SELECT Titre FROM Livres WHERE Parution>1900;
Titre ___________________________________ Le Petit Prince 1984 Le Seigneur des Anneaux Harry Potter à l'école des sorciers Fondation Dune |
Le mot clé WHERE est utilisé dans la plupart des requêtes. On peut également ajouter les mots clés AND et OR pour gérer de la logique.
Order By, Distinct et Fonctions d'agrégation
- ORDER BY permet de choisir un attribut pour trier les résultats. Il s'agit de l'ordre croissant par defaut, ORDER BY ... ASC, mais on peut choisir de trier dans l'ordre décroissant en écrivant ORDER BY ... DESC
- DISTINCT permet de n'afficher que des résultats distincts.
- Les fonctions d'agrégation sont un peu à part. Elles ne renvoient pas un tableau mais un résultat unique, calculé à partir des enregistrements retournés par SELECT :
- COUNT compte le nombre d'enregistrements retournés par la requête et n'affiche que le résultat.
- SUM affiche la somme des valeurs retournées par la requête et n'affiche que le résultat.
- AVG affiche la moyenne des valeurs retournées par la requête.
- MIN et MAX affichent la valeur minimale/maximale des valeurs retournées par la requête.
On peut aussi écrire la requête sur plusieurs lignes pour améliorer la lisibilité. C'est le point virgule qui valide la requête.
SELECT
FROM Livres
;
ID Titre Auteur Parution Genre Stock _________________________________________________________________________________________________________________ 101 Le Petit Prince Antoine de Saint-Exupéry 1943 Roman 4 102 1984 George Orwell 1949 Science-fiction 2 103 Orgueil et Préjugés Jane Austen 1813 Roman 3 104 Le Seigneur des Anneaux J.R.R. Tolkien 1954 Aventure 5 105 Harry Potter à l'école des sorciers J.K. Rowling 1997 Aventure 4 106 Les Misérables Victor Hugo 1862 Roman 3 107 Le Comte de Monte-Cristo Alexandre Dumas 1844 Aventure 6 108 Bel-Ami Guy de Maupassant 1885 Roman 4 109 Fondation Isaac Asimov 1951 Science-fiction 7 110 Dune Frank Herbert 1965 Science-fiction 5 |
Clause INSERT INTO : Création d'un enregistrement
Pour ajouter un enregistrement à une relation, on utilise le mot clé INSERT INTO, suivi de la table, puis du mot VALUES et des valeurs à ajouter, sous forme de tuple.
INSERT INTO Livres VALUES (111, 'L\'Assassin Royal', 'Robin Hobb', 1995, 'Aventure', 2);
Remarques
Trois remarques ici :
- On utilise des apostrophes pour délimiter les chaînes de caractères en SQL plutôt que les guillemets.
- Pensez donc à échapper les apostrophes présentes dans les noms avec le caractère backslash \.
- On peut également ajouter un enregistrement sans renseigner tous les attributs, mais il faut alors préciser lesquels on fournit. L'ordre n'est pas important :
INSERT INTO Livres (Auteur, Titre) VALUES ('H.P. Lovecraft', 'L\'appel de Cthulhu');
Clause UPDATE ... SET : Modification d'un enregistrement
On peut modifier les valeurs d'un enregistrement avec la clause UPDATE, suivie de la relation à modifier, puis SET suivi des attributs à modifier avec leur nouvelle valeur.
UPDATE Livres
SET Parution = 1928, Genre = 'Horreur', Stock = 4
WHERE Titre = 'L\Appel de Cthulhu';
Remarques
- En SQL, le symbole == n'existe pas. On utilise aussi le symbole = pour tester l'égalité dans une clasue WHERE.
- Il est très rare d'utiliser une clause UPDATE sans clause WHERE. Dans le cas contraire, on aurait modifié tous les enregistrement de la base et on leur aurait affecté les mêmes valeurs pour Parution, Genre et Stock. C'est un moyen assez classique d'altérer gravement une base de données.
Clause DELETE : Suppresion d'un enregistrement
Pour supprimer un enregistrement, on utilise les mots clés DELETE FROM, suivis de la table.
Là encore, dans la plupart des cas, on voudra ajouter une clause WHERE pour préciser les enregistrements à supprimer. Sinon, toutes les lignes sont supprimées et la table sera vide.
DELETE FROM Livres WHERE Stock = 0;
Clause JOIN : Jointure entre deux relations
Considérons le schéma relationnel suivant, utilisé pour un système de gestion de commandes.
- Clients (id INT, nom TEXT, email TEXT)
- Commandes (id INT, date DATE, montant REAL, #id_client INT)
Exemple:
| Clients | ||
|---|---|---|
| id | nom | |
| 1 | Dupont | dupont@example.com |
| 2 | Martin | martin@example.com |
| 3 | Bernard | bernard@example.com |
| Commandes | |||
|---|---|---|---|
| id | date | montant | id_client |
| 1001 | 2025-08-01 | 150.00 | 1 |
| 1002 | 2025-08-05 | 200.50 | 2 |
| 1003 | 2025-08-10 | 75.30 | 1 |
| 1004 | 2025-08-15 | 300.00 | 3 |
Supposons que l'on veuille contacter le client de la commande n°1004. Il n'y a pas de relation qui me permette directement de faire le lien entre l'id de commande, et l'adresse mail du client correspondant. Il faut donc que je me serve de la clé étrangère id_client de la relation commande, pour accéder à l'email du client correspondant dans la relation Clients. On pourrait le faire avec deux requêtes SELECT :
SELECT id_client FROM Commandes WHERE id=1004;
Le SGBD renverrait alors la valeur 3, qui me permettrait d'effectuer la requête suivante :
SELECT email FROM Clients WHERE id=3;
Le SGBD renverrait alors ce que je souhaitais au départ : l'adresse mail bernard@example.com
La clause JOIN permet de faire tout ceci en une seule requête :
SELECT Clients.email
FROM Clients JOIN Commandes
ON Commandes.id_client=Clients.id
WHERE Commandes.id=1004;
Explications
Décortiquons la requête, ligne par ligne :
- l1 :
- On souhaite lire une information dans la base, il s'agit donc bien d'une requête SELECT.
- Au final, tout ce qui m'intéresse est la valeur de l'attribut email de la relation Clients.
- La notation pointée permet d'éviter les conflits entre les noms d'attribut des différentes relations. Clients.email indique qu'il s'agit de l'attribut email de la relation Clients. Ce n'est pas obligatoire tant que tous les noms sont différents, mais c'est une bonne habitude à prendre dès qu'on utilise des requêtes avec plusieurs relations. Ici, il pourrait y avoir un conflit avec le nom id si on ne précise pas de quelle relation il s'agit.
- l2 : On fait une jointure : On indique que l'on récupère des informations depuis les deux relations Clients et Commandes que l'on relie ensemble.
- l3 : On précise comment on fait la jointure, autrement dit quelle est la conditions qui permet d'aligner les enregistrements de chaque relation. Ici, on associe les clés étrangères de la relation Commandes aux clés primaires correspondantes dans la relation Client.
- l4 : La clause WHERE permet de sélectionner uniquement la ligne qui contient l'id de commande 1004.
Jointures entre plus de deux tables
On peut aussi avoir besoin de faire des jointures entre plus de deux tables. Considérons le schéma relationnel suivant :
- Gares (id INT, nom TEXT, ville TEXT)
- Trains (id INT, numero TEXT, type TEXT)
- Voyages (id INT, #id_train TEXT, #id_gare_depart INT, #id_gare_arrivee INT, heure_depart DATETIME, heure_arrivee DATETIME)
Supposons que l'on souhaite connaître la liste de tous les numeros de train au départ de Toulon. Il faut utiliser la relation Gares pour connaître les noms des villes, la relation Voyages pour connaître les gares de départ, et la relation Trains pour les numéros de train. On peut faire une requête JOIN exactement de la même manière que précédemment.
Je vais en plus utiliser le mot clé AS pour créer des alias : des noms alternatifs qui me semblent plus pratiques à écrire.
SELECT t.numero
FROM Trains AS t
JOIN Voyages AS v
ON t.id=v.id_train
JOIN Gares AS g
ON g.id=v.id_gare_depart
WHERE g.ville='Toulon';

