SQL et Bases de Données Relationnelles

Classe SDA 7 2025-2026

Module 4

Les Jointures - L'Art de Connecter les Données

1. Le Problème : Les Données sont Séparées, Comment les Réunir ?

Dans le module précédent, nous avons intelligemment séparé nos données dans des tables distinctes pour éviter la redondance. C'est la bonne pratique. Mais cela crée un nouveau défi : comment répondre à une question simple qui nécessite des informations de plusieurs tables ?

Question métier

"Afficher le nom de chaque client à côté du nom du produit qu'il a commandé."

Le nom du client est dans la table utilisateurs. Le nom du produit est dans la table commandes. La jointure (JOIN) est l'opération SQL magique qui nous permet de "reconstituer" temporairement une vue unifiée de ces tables en se basant sur leur relation.

2. Mise en Place : Nos Tables pour les Exemples

Pour tous les exemples suivants, nous utiliserons ces deux tables :

→ Table utilisateurs (alias u) :
id nom
1 Alice
2 Bob
3 Charlie
→ Table commandes (alias c) :
id produit utilisateur_id
101 Livre 1
102 Ordinateur 2
103 Stylo 1
104 Clavier 4

Notez que Charlie (id=3) n'a pas de commande, et que la commande de Clavier (id=104) a un utilisateur_id (4) qui n'existe pas dans notre table utilisateurs.

Les Types de Jointures Expliqués

1. INNER JOIN (L'Intersection Stricte)

Ce qu'elle fait : Renvoie uniquement les lignes pour lesquelles il existe une correspondance dans les deux tables. C'est la jointure la plus courante et la plus restrictive.

Question type : "Montre-moi uniquement les utilisateurs QUI ONT passé une commande, et les produits qu'ils ont achetés."

Visualisation Venn : La zone centrale où les deux cercles se chevauchent.

SELECT u.nom, c.produit FROM utilisateurs AS u INNER JOIN commandes AS c ON u.id = c.utilisateur_id;
  • AS u et AS c sont des alias, des surnoms pour les noms de table qui rendent la requête plus courte et plus lisible. C'est une pratique indispensable.
  • ON u.id = c.utilisateur_id est la condition de jointure. C'est le "câble" qui dit à SQL comment relier les lignes : "connecte une ligne de utilisateurs à une ligne de commandes lorsque l'id de l'utilisateur est égal à l'utilisateur_id de la commande".

Résultat :

nom produit
Alice Livre
Bob Ordinateur
Alice Stylo

(Charlie est exclu car il n'a pas de correspondance dans commandes. La commande "Clavier" est exclue car son utilisateur_id 4 n'a pas de correspondance dans utilisateurs.)

2. LEFT JOIN (La Priorité à Gauche)

Ce qu'elle fait : Renvoie toutes les lignes de la table de gauche (celle déclarée dans FROM), et les lignes correspondantes de la table de droite. S'il n'y a pas de correspondance à droite, les colonnes de cette table seront remplies avec la valeur NULL.

Question type : "Montre-moi tous les utilisateurs, et affiche les commandes qu'ils ont passées, s'ils en ont."

Visualisation Venn : Le cercle entier de gauche, y compris la partie qui intersecte le cercle de droite.

SELECT u.nom, c.produit FROM utilisateurs AS u LEFT JOIN commandes AS c ON u.id = c.utilisateur_id;

Résultat :

nom produit
Alice Livre
Alice Stylo
Bob Ordinateur
Charlie NULL

(Charlie apparaît maintenant, car il est dans la table de gauche, mais avec NULL pour le produit car il n'a pas de commande correspondante.)

3. RIGHT JOIN (La Priorité à Droite)

Ce qu'elle fait : C'est l'inverse exact du LEFT JOIN. Elle renvoie toutes les lignes de la table de droite (celle déclarée dans JOIN), et les correspondances de la table de gauche.

Question type : "Montre-moi toutes les commandes, et le nom de l'utilisateur qui les a passées, s'il existe."

SELECT u.nom, c.produit FROM utilisateurs AS u RIGHT JOIN commandes AS c ON u.id = c.utilisateur_id;

Résultat :

nom produit
Alice Livre
Bob Ordinateur
Alice Stylo
NULL Clavier

(La commande "Clavier" apparaît maintenant, car elle est dans la table de droite, mais avec NULL pour le nom car son utilisateur_id 4 n'existe pas dans la table utilisateurs.)

4. FULL OUTER JOIN (Tout Inclure)

Ce qu'elle fait : Renvoie toutes les lignes des deux tables. Lorsqu'il y a une correspondance, les données des deux côtés sont affichées. Lorsqu'il n'y a pas de correspondance, des NULL apparaissent du côté manquant.

Question type : "Montre-moi tous les utilisateurs ET toutes les commandes, qu'ils soient liés ou non."

Visualisation Venn : Les deux cercles en entier.

SELECT u.nom, c.produit FROM utilisateurs AS u FULL OUTER JOIN commandes AS c ON u.id = c.utilisateur_id;

Résultat :

nom produit
Alice Livre
Alice Stylo
Bob Ordinateur
Charlie NULL
NULL Clavier

Note : MySQL ne supporte pas directement FULL OUTER JOIN. Vous pouvez obtenir le même résultat en combinant LEFT JOIN et RIGHT JOIN avec UNION.

3. Jointures Multiples : Relier Plus de Deux Tables

Dans les applications réelles, vous devrez souvent joindre trois tables ou plus. La logique reste la même : vous enchaînez simplement plusieurs JOIN.

Exemple avec trois tables

Imaginons que nous ajoutons une table categories pour classifier nos produits :

-- Créer une table categories CREATE TABLE categories ( id INT PRIMARY KEY, nom_categorie VARCHAR(50) ); -- Ajouter une colonne categorie_id dans commandes ALTER TABLE commandes ADD COLUMN categorie_id INT; -- Exemple de jointure multiple SELECT u.nom AS utilisateur, c.produit, cat.nom_categorie AS categorie FROM utilisateurs AS u INNER JOIN commandes AS c ON u.id = c.utilisateur_id INNER JOIN categories AS cat ON c.categorie_id = cat.id;

Ici, nous lions trois tables en chaînant deux INNER JOIN. L'ordre des jointures est important pour la lisibilité, mais SQL optimisera l'exécution automatiquement.

4. Erreurs Courantes et Pièges à Éviter

⚠️ Oublier la clause ON

Si vous omettez la condition ON, vous créerez un produit cartésien : chaque ligne de la première table sera associée à chaque ligne de la seconde table. Pour 100 utilisateurs et 1000 commandes, cela génère 100 000 lignes !

-- ❌ ERREUR : Produit cartésien SELECT * FROM utilisateurs, commandes; -- ✅ CORRECT : Avec condition de jointure SELECT * FROM utilisateurs u INNER JOIN commandes c ON u.id = c.utilisateur_id;
⚠️ Confusion entre LEFT et RIGHT JOIN

Rappelez-vous : LEFT JOIN garde toutes les lignes de la table de gauche (après FROM), RIGHT JOIN garde toutes les lignes de la table de droite (après JOIN).

Astuce : La plupart des développeurs utilisent principalement LEFT JOIN car c'est plus intuitif (on part de la table principale). Un RIGHT JOIN peut toujours être réécrit comme un LEFT JOIN en inversant l'ordre des tables.

⚠️ Ambiguïté des noms de colonnes

Si deux tables ont des colonnes avec le même nom (comme id), vous devez toujours préciser à quelle table appartient la colonne en utilisant les alias.

-- ❌ ERREUR : Ambiguïté SELECT id, nom FROM utilisateurs u INNER JOIN commandes c ON u.id = c.utilisateur_id; -- ✅ CORRECT : Colonnes préfixées SELECT u.id, u.nom, c.id AS commande_id FROM utilisateurs u INNER JOIN commandes c ON u.id = c.utilisateur_id;

5. Cas d'Usage Réels : La Boutique en Ligne

Reprenons l'exemple de la boutique en ligne du quiz. Voici des requêtes concrètes utilisant les jointures :

Cas 1 : Liste des commandes avec les informations clients

SELECT c.id AS numero_commande, cl.nom AS client, cl.ville, c.date_commande, c.montant_total FROM Commandes c INNER JOIN Clients cl ON c.client_id = cl.id ORDER BY c.date_commande DESC;

Cas 2 : Trouver les clients qui n'ont jamais commandé

SELECT cl.nom, cl.email FROM Clients cl LEFT JOIN Commandes c ON cl.id = c.client_id WHERE c.id IS NULL;

Cette technique utilise LEFT JOIN puis filtre sur WHERE c.id IS NULL pour ne garder que les clients sans commande correspondante.

Cas 3 : Détail complet d'une commande avec produits

SELECT cl.nom AS client, c.date_commande, p.nom_produit, p.prix, dc.quantite, (p.prix * dc.quantite) AS sous_total FROM Commandes c INNER JOIN Clients cl ON c.client_id = cl.id INNER JOIN Details_Commande dc ON c.id = dc.commande_id INNER JOIN Produits p ON dc.produit_id = p.id WHERE c.id = 1;

Cette requête joint 4 tables pour afficher tous les détails d'une commande spécifique.

6. Performance et Optimisation des Jointures

💡 Impact sur les performances

Les jointures peuvent devenir coûteuses sur de grandes tables. Voici quelques points clés :

  • Indexez vos clés étrangères : Un index sur les colonnes utilisées dans la clause ON accélère considérablement les jointures.
  • Limitez les colonnes sélectionnées : Évitez SELECT *, ne demandez que les colonnes nécessaires.
  • Filtrez tôt : Utilisez WHERE pour réduire le nombre de lignes avant d'effectuer les jointures.
  • Ordre des jointures : Commencez par les tables les plus petites ou les plus filtrées.

Exemple d'optimisation

-- ❌ Moins optimal : Jointure puis filtrage SELECT u.nom, c.produit FROM utilisateurs u INNER JOIN commandes c ON u.id = c.utilisateur_id WHERE u.ville = 'Paris'; -- ✅ Plus optimal : Filtrage puis jointure (avec sous-requête) SELECT u.nom, c.produit FROM (SELECT * FROM utilisateurs WHERE ville = 'Paris') u INNER JOIN commandes c ON u.id = c.utilisateur_id;

Note : Les SGBD modernes optimisent automatiquement ces requêtes, mais il est bon de comprendre le principe.

7. À Vous de Jouer : Exercices Pratiques

📝 Exercice 1

En utilisant les tables utilisateurs et commandes présentées plus haut, écrivez une requête pour afficher tous les produits commandés par Alice.

Indice : Utilisez un INNER JOIN et une clause WHERE.

📝 Exercice 2

Écrivez une requête qui affiche le nom de tous les utilisateurs, ainsi que le nombre de commandes qu'ils ont passées (y compris 0 pour ceux qui n'ont jamais commandé).

Indice : Utilisez un LEFT JOIN avec COUNT() et GROUP BY.

📝 Exercice 3

Trouvez toutes les commandes qui n'ont pas d'utilisateur valide (comme la commande "Clavier" avec utilisateur_id = 4).

Indice : Utilisez un LEFT JOIN inversé ou un RIGHT JOIN avec WHERE ... IS NULL.

Pour aller plus loin en vidéo

Source: Zak ISMAILI

Bonnes Pratiques pour les Jointures

Utilisez toujours des alias

C'est indispensable pour la lisibilité, surtout quand vous joignez plus de deux tables.

Soyez précis dans votre SELECT

Évitez SELECT * avec des jointures. Si deux tables ont une colonne avec le même nom (ex: id), cela peut créer une ambiguïté. Spécifiez toujours les colonnes que vous voulez en les préfixant avec leur alias : SELECT u.id, u.nom, c.id, c.produit.

Indexez vos clés étrangères

Pour que les jointures sur de grandes tables soient rapides, assurez-vous que les colonnes utilisées dans la clause ON (généralement les clés étrangères) ont un index. (Nous verrons cela dans le module sur l'optimisation).