- Publié le
Qu’est-ce que SQL ? Comprendre son rôle, ses origines et son utilisation
- Auteurs
Qu’est-ce que SQL ? Comprendre son rôle, ses origines et son utilisation
La plupart des applications modernes, du simple blog aux immenses réseaux sociaux, stockent et récupèrent leurs données avec un langage appelé SQL.
Dans cet article, vous découvrirez :
- Ce qu’est SQL et pourquoi il a été créé
- Comment les bases relationnelles organisent les informations
- Un exemple concret avec deux tables
- Comment exécuter de vraies requêtes SQL, notamment des
JOIN - Pourquoi SQL reste la référence après plus de 50 ans
Commençons.
Qu’est-ce que SQL ?
SQL (Structured Query Language) est un langage de programmation déclaratif créé pour gérer les bases de données relationnelles, organisées autour de tables, de lignes et des relations entre elles.
SQL permet de :
- Créer des tables
- Insérer et modifier des données
- Interroger les données avec des filtres
- Joindre des données liées provenant de plusieurs tables
- Imposer des contraintes, comme l’unicité des adresses courriel ou les clés étrangères
SQL est utilisé dans de nombreux systèmes de bases relationnelles populaires. Voici quelques exemples :
- PostgreSQL : une base relationnelle open source avancée avec une prise en charge solide des standards SQL.
- MySQL : largement utilisé dans les applications web, connu pour sa rapidité et sa simplicité.
- MariaDB : une version dérivée de MySQL portée par la communauté, avec des fonctionnalités améliorant les performances.
- SQLite : une base légère fondée sur un fichier, utilisée dans les applications mobiles, les navigateurs et les systèmes embarqués.
- Microsoft SQL Server : une base commerciale de niveau entreprise avec des outils solides pour Windows et les environnements cloud.
- Des services SQL entièrement gérés dans le cloud, comme :
- Amazon RDS
- Google Cloud SQL
- PlanetScale Ces plateformes, Amazon RDS, Google Cloud SQL et PlanetScale, gèrent les sauvegardes, la montée en charge, les mises à jour et la maintenance tout en conservant la puissance de SQL.
Pourquoi SQL a été créé
Dans les années 1970, chez IBM, les chercheurs Edgar F. Codd et Donald Chamberlin travaillaient sur une meilleure façon de stocker et de récupérer les données. À l’époque, les bases étaient hiérarchiques ou en réseau, et interagir avec elles était :
- Complexe
- Source d’erreurs
- Étroitement lié au stockage physique
- Difficile à adapter à des requêtes flexibles
Pour résoudre cela, ils ont introduit le modèle relationnel, qui organise les données dans des tables avec des relations bien définies.
SQL a été créé parce que :
- Les développeurs avaient besoin d’un langage simple et lisible pour interroger les données.
- Les entreprises avaient besoin de règles cohérentes pour stocker les relations.
- Les données devaient être accessibles sans connaître les détails internes du stockage.
Le résultat ? SQL est devenu un standard en 1986, avec ANSI SQL, et presque toutes les grandes bases actuelles reposent encore sur lui.
Comprendre les tables, les colonnes et les relations
Dans une base relationnelle :
- Une table ressemble à une feuille de calcul, avec des lignes et des colonnes
- Une ligne représente un enregistrement
- Une colonne représente une propriété
- Une clé primaire identifie chaque ligne de manière unique
- Une clé étrangère relie une table à une autre
Examinons un exemple simple avec des utilisateurs et des commandes.
Exemple de schéma : utilisateurs et commandes
Table 1 : users
| id | name (nom) | email (courriel) |
|---|---|---|
| 1 | Alice | alice@example.com |
| 2 | Bob | bob@example.com |
| 3 | Caroline | caroline@example.com |
Table 2 : orders
| id | user_id | product (produit) | price (prix) |
|---|---|---|---|
| 1 | 1 | Tasse à café | 12.99 |
| 2 | 1 | Sweat à capuche | 39.99 |
| 3 | 2 | Autocollants | 4.99 |
Relation
- Chaque commande appartient à un utilisateur, avec
orders.user_id → users.id. - Un utilisateur peut avoir plusieurs commandes, une relation de type un-à-plusieurs.
Créer les tables : exemple SQL
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
product TEXT NOT NULL,
price NUMERIC(10,2) NOT NULL
);
Cela crée deux tables relationnelles fortement typées avec une contrainte de clé étrangère. Mais que signifie « fortement typées » ? Dans des bases SQL comme PostgreSQL et MySQL, chaque colonne possède un type de données strict :
- Les chaînes doivent être des chaînes
- Les nombres doivent être des nombres
- Les dates doivent être des dates
- Les types incorrects provoquent des erreurs
Cela évite des erreurs comme :
- Enregistrer « vingt dollars » dans une colonne numérique
- Enregistrer 123 dans un champ d’adresse courriel
- Enregistrer des dates invalides
SQLite fonctionne différemment : son typage est flexible, ou dynamique, et les types y sont imposés moins strictement. PostgreSQL est la plus fortement typée des grandes bases de données.
Création des tables expliquée ligne par ligne
Table 1 : users
CREATE TABLE users (
Explication : Cette instruction commence la création d’une table nommée users.
- Fonctionne dans PostgreSQL, MySQL, MariaDB, SQLite et SQL Server.
- Une « table » est un ensemble structuré de lignes et de colonnes dans la base.
id SERIAL PRIMARY KEY,
Explication :
id → Le nom de la colonne.
SERIAL → Un entier auto-incrémenté, propre à PostgreSQL.
Équivalents dans les autres moteurs :
- MySQL :
INT AUTO_INCREMENT - SQLite :
INTEGER PRIMARY KEY AUTOINCREMENT
- MySQL :
PRIMARY KEY → Garantit l’unicité et identifie chaque ligne.
name TEXT NOT NULL,
Explication :
- name → Une colonne pour stocker du texte.
- TEXT → Du texte de longueur variable, une chaîne de caractères.
- NOT NULL → Ne peut pas être vide.
Fonctionne dans PostgreSQL, MySQL, MariaDB et SQLite. SQL Server utilise toutefois VARCHAR(MAX) à la place de TEXT.
email TEXT UNIQUE NOT NULL
Explication :
- email → Stocke l’adresse courriel de l’utilisateur.
- TEXT → Le type texte.
- UNIQUE → Empêche les adresses courriel en double.
- NOT NULL → Un champ obligatoire.
Fonctionne dans PostgreSQL, MySQL, MariaDB et SQLite, en tenant compte des différences internes du type TEXT.
);
Explication : Ferme la définition de la table.
Table 2 : orders
CREATE TABLE orders (
Commence une table nommée orders. Fonctionne dans tous les principaux moteurs.
id SERIAL PRIMARY KEY,
Même sens que dans la table users :
- Clé primaire auto-incrémentée
- Type propre à PostgreSQL,
SERIAL - MySQL utilise
INT AUTO_INCREMENT - SQLite utilise
INTEGER PRIMARY KEY AUTOINCREMENT
user_id INTEGER NOT NULL REFERENCES users(id),
Explication :
- user_id → Un nombre qui relie la commande à une ligne de
users. - INTEGER → Un nombre entier.
- NOT NULL → Chaque commande doit appartenir à un utilisateur.
- REFERENCES users(id) → Une contrainte de clé étrangère.
Sens de clé étrangère :
- Garantit que
user_idcorrespond à un véritableiddans la tableusers. - Si un utilisateur est supprimé, la base applique la relation selon les règles de clé étrangère.
Compatibilité des moteurs :
- PostgreSQL : entièrement pris en charge.
- MySQL/MariaDB : fonctionne, mais exige le moteur de stockage InnoDB.
- SQLite : pris en charge uniquement si la gestion des clés étrangères est activée, avec
PRAGMA foreign_keys = ON;.
product TEXT NOT NULL,
Stocke le nom du produit acheté.
- Le type TEXT fonctionne différemment selon les moteurs, mais stocke toujours des chaînes.
- Champ obligatoire avec
NOT NULL.
price NUMERIC(10,2) NOT NULL
Explication :
price → Le coût du produit.
NUMERIC(10,2) → Un nombre à précision fixe avec :
- Jusqu’à 10 chiffres au total
- 2 chiffres après la virgule
Ce type convient aux montants monétaires, car il évite les erreurs de calcul en virgule flottante.
Compatibilité des moteurs :
- PostgreSQL : prise en charge complète.
- MySQL :
DECIMAL(10,2)est équivalent. - SQLite : l’accepte, mais stocke les valeurs en interne en TEXT, INT ou REAL, selon son typage dynamique.
);
Termine la table.
Insérer les données d’exemple
Maintenant que les tables sont créées, insérons les données d’exemple présentées plus haut. Nous ne fournirons pas manuellement de valeurs id. La base les générera automatiquement avec le type auto-incrémenté SERIAL.
Insérer les données de users
INSERT INTO users (name, email)
VALUES
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com'),
('Caroline', 'caroline@example.com');
Insertion dans users expliquée ligne par ligne
INSERT INTO users (name, email)
INSERT INTO usersNous ajoutons des lignes à la table users.(name, email)Nous fournissons uniquementnameetemail, pasid.Pourquoi ne pas fournir l’identifiant ? Comme la colonne
idutilise un type serial/auto-incrémenté, leSERIALde PostgreSQL, la base crée automatiquement les identifiants :Premier utilisateur →
id = 1Deuxième utilisateur →
id = 2Troisième utilisateur →
id = 3
Ce fonctionnement est prévisible dans PostgreSQL, MySQL, MariaDB et SQLite, avec leurs mécanismes respectifs d’auto-incrémentation.
VALUES
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com'),
('Caroline', 'caroline@example.com');
VALUESintroduit une liste de lignes à insérer.- Chaque groupe
( ... )correspond à une nouvelle ligne. - La base attribue automatiquement les identifiants dans l’ordre d’apparition des lignes.
Table users après insertion :
| id | name (nom) | email (courriel) |
|---|---|---|
| 1 | Alice | alice@example.com |
| 2 | Bob | bob@example.com |
| 3 | Caroline | caroline@example.com |
Même si nous n’avons écrit aucun identifiant manuellement, le mécanisme d’auto-incrémentation assure cet ordre.
Insérer les données de orders
Pour insérer dans orders, nous devons fournir user_id, car une commande doit appartenir à un utilisateur précis.
Même si nous n’avons pas fixé manuellement les identifiants des utilisateurs, nous connaissons leurs valeurs :
- Alice → Identifiant 1
- Bob → Identifiant 2
- Caroline → Identifiant 3
Ils ont été générés automatiquement dans l’ordre d’insertion. L’auto-incrémentation attribue toujours les identifiants séquentiellement, sauf si des lignes sont supprimées.
Voici l’insertion :
INSERT INTO orders (user_id, product, price)
VALUES
(1, 'Coffee Mug', 12.99),
(1, 'Hoodie', 39.99),
(2, 'Stickers', 4.99);
Insertion dans orders expliquée ligne par ligne
INSERT INTO orders (user_id, product, price)
Nous insérons de nouvelles lignes dans la table orders.
Nous précisons :
user_id→ L’utilisateur auquel appartient la commandeproduct→ Le nomprice→ Le coût
Remarquez à nouveau que nous ne fournissons pas id (orders.id), car il s’auto-incrémente.
VALUES
(1, 'Coffee Mug', 12.99),
(1, 'Hoodie', 39.99),
(2, 'Stickers', 4.99);
(1, 'Coffee Mug', 12.99)- Cette commande appartient à l’utilisateur 1, Alice.
(1, 'Hoodie', 39.99)- Une autre commande pour Alice.
(2, 'Stickers', 4.99)- Une commande pour l’utilisateur 2, Bob.
Comment connaître l’identifiant de chaque utilisateur ? Parce que :
Les utilisateurs ont été insérés en premier.
Les identifiants auto-incrémentés sont toujours des entiers séquentiels.
Par conséquent :
- Premier utilisateur inséré → Identifiant 1
- Deuxième utilisateur inséré → Identifiant 2
- Troisième utilisateur inséré → Identifiant 3
Il est ainsi entièrement prévisible de référencer les utilisateurs par leur identifiant.
Tables finales obtenues
users
| id | name (nom) | email (courriel) |
|---|---|---|
| 1 | Alice | alice@example.com |
| 2 | Bob | bob@example.com |
| 3 | Caroline | caroline@example.com |
orders
| id | user_id | product (produit) | price (prix) |
|---|---|---|---|
| 1 | 1 | Tasse à café | 12.99 |
| 2 | 1 | Sweat à capuche | 39.99 |
| 3 | 2 | Autocollants | 4.99 |
Interroger les données avec SQL
Voici des requêtes SQL que nous pouvons exécuter sur les deux tables définies plus haut.
1. Sélectionner tous les utilisateurs
SELECT * FROM users;
Résultat :
| id | name (nom) | email (courriel) |
|---|---|---|
| 1 | Alice | alice@example.com |
| 2 | Bob | bob@example.com |
| 3 | Caroline | caroline@example.com |
2. Sélectionner les utilisateurs avec un filtre
SELECT * FROM users
WHERE email LIKE '%alice@example.com';
Signification :
LIKEest un opérateur SQL qui compare du texte à l’aide de motifs.%est un caractère générique qui correspond à n’importe quel nombre de caractères, y compris aucun.
Ainsi :
'%alice@example.com'signifie : « Rechercher tout texte qui se termine paralice@example.com. »
Cela renvoie la ligne dont l’adresse courriel est exactement :
alice@example.com
Mais correspondrait aussi à des valeurs comme :
test-alice@example.comhello.alice@example.comanythingalice@example.com
Si elles existaient.
Résultat :
| id | name (nom) | email (courriel) |
|---|---|---|
| 1 | Alice | alice@example.com |
Cette requête renvoie uniquement l’utilisateur dont l’adresse courriel correspond au filtre.
3. Insérer une nouvelle commande
INSERT INTO orders (user_id, product, price)
VALUES (2, 'T-Shirt', 29.99);
Table orders après insertion :
| id | user_id | product (produit) | price (prix) |
|---|---|---|---|
| 1 | 1 | Tasse à café | 12.99 |
| 2 | 1 | Sweat à capuche | 39.99 |
| 3 | 2 | Autocollants | 4.99 |
| 4 | 2 | T-shirt | 29.99 |
- La nouvelle ligne possède
id = 4, généré automatiquement.user_id = 2relie cette commande à Bob.
Les jointures : une fonctionnalité puissante de SQL
Les jointures permettent d’interroger des données liées dans plusieurs tables.
Explorons-les avec nos tables users et orders.
Exemple 1 : INNER JOIN, le plus courant
Récupérer chaque commande avec l’utilisateur qui l’a passée.
SELECT users.name, orders.product, orders.price
FROM orders
INNER JOIN users
ON orders.user_id = users.id;
Résultat :
| name (nom) | product (produit) | price (prix) |
|---|---|---|
| Alice | Tasse à café | 12.99 |
| Alice | Sweat à capuche | 39.99 |
| Bob | Autocollants | 4.99 |
| Bob | T-shirt | 29.99 |
Bob apparaît désormais deux fois à cause de la nouvelle commande insérée précédemment :
INSERT INTO orders (user_id, product, price)
VALUES (2, 'T-Shirt', 29.99);
Exemple 2 : LEFT JOIN
Récupérer tous les utilisateurs, même ceux qui n’ont pas de commande.
SELECT users.name, orders.product
FROM users
LEFT JOIN orders
ON users.id = orders.user_id;
Résultat :
| name (nom) | product (produit) |
|---|---|
| Alice | Tasse à café |
| Alice | Sweat à capuche |
| Bob | Autocollants |
| Bob | T-shirt |
| Caroline | null |
Caroline apparaît avec null, car elle n’a pas de commande.
Exemple 3 : requête d’agrégation
Montant total dépensé par chaque utilisateur :
SELECT users.name, SUM(orders.price) AS total_spent
FROM users
LEFT JOIN orders ON users.id = orders.user_id
GROUP BY users.name;
Résultat :
| name (nom) | total_spent (total dépensé) |
|---|---|
| Alice | 52.98 |
| Bob | 34.98 |
| Caroline | null |
Explication
- Alice : 12.99 + 39.99 = 52.98
- Bob : 4.99 + 29.99 = 34.98
- Caroline : aucune commande → NULL
Où en apprendre davantage ?
Pour terminer
SQL existe depuis plus de 50 ans et fait toujours fonctionner les applications les plus importantes au monde, car il est :
- Déclaratif
- Cohérent
- Prévisible
- Capable de monter en charge
- Soutenu par des décennies de recherche
Une fois le fonctionnement des tables et des jointures compris, SQL devient l’un des outils les plus puissants de votre boîte à outils de programmation.