Maintenez SQLtest en vie : Aidez à couvrir les coûts du serveur de ce mois-ci de 100 $ pour garder toutes les leçons et le terrain de jeu SQL en ligne. Soutenez le projet →
Code SQL copié dans le presse-papiers

Leçon 5.8 · Temps de lecture : ~8 min

Cette leçon rassemble des scénarios pratiques de SQL JOIN : joindre plusieurs tables en suivant les relations du schéma, agréger des données jointes, trouver des données manquantes, et éviter les deux erreurs de jointure les plus courantes : les totaux gonflés et les jointures externes qui perdent leurs lignes.

Scénarios pratiques de SQL JOIN

Vous connaissez les types de jointures ; il s'agit maintenant de les appliquer à de vraies questions. La plupart des requêtes de rapport suivent les mêmes étapes : trouver les tables qui contiennent les données, les relier par leurs clés, filtrer et agréger.

Jointures SQL en pratique : un chemin dans le schéma du client au paiement et du film à la catégorie, l'agrégation après une jointure, et la multiplication de lignes qui gonfle les sommes

Planifier le chemin de jointure

Partez de la question et trouvez un chemin entre les tables dans le diagramme de la base. « Le chiffre d'affaires par catégorie de film » nécessite category, puis film_category, inventory, rental et enfin payment :

SELECT c.name AS category,
       COUNT(p.payment_id) AS payments,
       SUM(p.amount) AS revenue
FROM category AS c
INNER JOIN film_category AS fc ON fc.category_id = c.category_id
INNER JOIN inventory AS i ON i.film_id = fc.film_id
INNER JOIN rental AS r ON r.inventory_id = i.inventory_id
INNER JOIN payment AS p ON p.rental_id = r.rental_id
GROUP BY c.name
ORDER BY revenue DESC;

Résultat : 16 catégories triées par chiffre d'affaires ; Sports et Sci-Fi arrivent en tête.

La table film elle-même n'est pas nécessaire : film_category et inventory stockent toutes deux film_id, on peut donc les joindre directement. Ne joignez que les tables qui contiennent des données ou qui sont nécessaires pour les relier.


Agréger après une jointure

Le total des dépenses de chaque client :

SELECT c.customer_id,
       c.first_name,
       c.last_name,
       COUNT(*) AS payments,
       SUM(p.amount) AS total_spent
FROM customer AS c
INNER JOIN payment AS p ON p.customer_id = c.customer_id
GROUP BY c.customer_id, c.first_name, c.last_name
ORDER BY total_spent DESC
LIMIT 10;

Résultat : les 10 clients qui ont le plus dépensé.

Groupez par la clé (customer_id), pas seulement par le nom : deux clients différents peuvent avoir le même nom.


Le piège de la multiplication des lignes : des totaux gonflés

Une jointure multiplie les lignes : un client avec 30 paiements et 30 locations devient 900 lignes si les deux tables sont jointes au client en même temps. Toute somme sur un tel résultat est fausse.

-- Faux : les paiements sont multipliés par les locations
SELECT c.customer_id,
       SUM(p.amount) AS total_spent
FROM customer AS c
INNER JOIN payment AS p ON p.customer_id = c.customer_id
INNER JOIN rental AS r ON r.customer_id = c.customer_id
WHERE c.customer_id = 1
GROUP BY c.customer_id;

Résultat : 3 797,76 au lieu des 118,68 réels : chacun des 32 paiements du client a été compté une fois pour chacune de ses 32 locations.

La règle : ne joignez pas deux tables « plusieurs » indépendantes à la même ligne dans une seule requête. Ici, la table rental n'est pas du tout nécessaire. Quand vous avez besoin de totaux issus de deux tables de ce type, agrégez d'abord chacune séparément ; vous verrez comment avec les sous-requêtes et les CTE dans le module 6.


Trouver des données manquantes

LEFT JOIN ... WHERE right_key IS NULL trouve les lignes sans correspondance. Les clients qui n'ont rien loué depuis le 23 août 2005 :

SELECT c.customer_id, c.first_name, c.last_name
FROM customer AS c
LEFT JOIN rental AS r ON r.customer_id = c.customer_id
                     AND r.rental_date >= '2005-08-23'
WHERE r.rental_id IS NULL
ORDER BY c.customer_id;

Résultat : les clients sans location dans les derniers jours des données.

Notez la condition de date : elle est dans ON, car elle limite les locations qui comptent comme correspondance. Dans WHERE, elle supprimerait tous les clients sans correspondance, et la requête ne renverrait rien.


WHERE ou ON dans les jointures externes

L'exemple précédent illustre la règle générale pour LEFT JOIN :

Condition surÀ placer dansEffet
la table de droite, pour limiter les correspondancesONLes lignes de gauche restent ; seules les correspondances sont filtrées
la table de gaucheWHERELes lignes de gauche sont retirées du résultat
la clé de la table de droite IS NULLWHERENe garde que les lignes sans correspondance (anti-jointure)

Pour INNER JOIN, ON et WHERE donnent le même résultat ; l'emplacement est donc une question de lisibilité.


Points clés :

  • Planifiez le chemin de jointure dans le schéma et ne joignez que les tables nécessaires.
  • Groupez par les clés, pas seulement par les noms.
  • Joindre deux tables « plusieurs » à la même ligne multiplie les lignes et gonfle les sommes et les comptages.
  • LEFT JOIN ... WHERE key IS NULL trouve les données manquantes.
  • Dans les jointures externes, les conditions sur la table de droite vont dans ON.

Questions fréquentes

Comment joindre plus de deux tables en SQL ?

Ajoutez un JOIN ... ON ... par table, en suivant les clés étrangères du schéma. Chaque jointure relie une nouvelle table à celles déjà présentes dans la requête.

Pourquoi mon SUM renvoie-t-il un nombre beaucoup plus grand après un JOIN ?

Parce que la jointure a multiplié les lignes : chaque ligne d'une table a été répétée pour chaque ligne correspondante d'une autre. Supprimez les tables inutiles, ou agrégez chaque table séparément avant de joindre les résultats.

Un filtre doit-il aller dans ON ou dans WHERE ?

Pour INNER JOIN, cela ne change rien. Pour LEFT JOIN, une condition sur la table de droite va dans ON ; dans WHERE, elle supprime les lignes sans correspondance et transforme la jointure externe en jointure interne.

Essayez de resoudre les exercices suivants pour consolider ce que vous avez appris dans cette lecon.

  1. Catalogue des produits