Aller au contenu

Module 2 : CTEs (Common Table Expressions)

·3 mins·
SQL Formation
SQL - Cet article fait partie d'une série.
Partie 2: Cet article

🔁 Module 2 – CTEs (Common Table Expressions)
#


🎯 Objectifs du module
#

À la fin, tu sauras :

  • Écrire des CTEs pour rendre ton SQL plus lisible
  • ChaĂźner des requĂȘtes complexes avec plusieurs Ă©tapes
  • Écrire une CTE rĂ©cursive (pour hiĂ©rarchie, arborescence, etc.)
  • Appliquer ça Ă  des cas rĂ©els d’analyse de donnĂ©es

🧠 C’est quoi une CTE ?
#

Une CTE est comme une vue temporaire et nommĂ©e dans une requĂȘte. Elle te permet de :

  • Casser une requĂȘte en plusieurs morceaux lisibles
  • RĂ©utiliser des sous-ensembles intermĂ©diaires
  • Éviter les sous-requĂȘtes imbriquĂ©es illisibles

📌 Syntaxe de base :
#

WITH alias AS (
  SELECT ...
)
SELECT * FROM alias;

Tu peux en chaĂźner plusieurs :

WITH
  step1 AS (SELECT ...),
  step2 AS (SELECT * FROM step1 WHERE ...)
SELECT * FROM step2;

đŸ› ïž Dataset de base
#

On garde notre dataset de clients et commandes du module précédent.


✅ Exemple 1 – CTE pour simplifier une agrĂ©gation
#

WITH commandes_par_client AS (
  SELECT client_id, COUNT(*) AS nb_commandes
  FROM commandes
  GROUP BY client_id
)
SELECT c.nom, cpc.nb_commandes
FROM clients c
LEFT JOIN commandes_par_client cpc ON c.client_id = cpc.client_id;

👉 On sĂ©pare l’agrĂ©gation de la jointure = plus lisible, modulaire.


✅ Exemple 2 – Plusieurs CTEs
#

WITH
  commandes_par_client AS (
    SELECT client_id, COUNT(*) AS nb_commandes
    FROM commandes
    GROUP BY client_id
  ),
  clients_avec_commandes AS (
    SELECT * FROM clients WHERE client_id IN (SELECT client_id FROM commandes)
  )
SELECT cac.nom, cpc.nb_commandes
FROM clients_avec_commandes cac
JOIN commandes_par_client cpc ON cac.client_id = cpc.client_id;

✅ Exemple 3 – Remplacer une sous-requĂȘte
#

-- Moins lisible
SELECT nom
FROM clients
WHERE client_id IN (
  SELECT client_id FROM commandes WHERE produit = 'Chaise'
);

-- Mieux avec une CTE
WITH acheteurs_chaise AS (
  SELECT client_id FROM commandes WHERE produit = 'Chaise'
)
SELECT c.nom
FROM clients c
JOIN acheteurs_chaise ac ON c.client_id = ac.client_id;

🔄 CTEs rĂ©cursives : cas typique = hiĂ©rarchies, arbres
#

💡 On utilise le mot-clĂ© spĂ©cial RECURSIVE dans le WITH

✅ Exemple 4 – Trouver tous les subordonnĂ©s d’un manager
#

WITH RECURSIVE hierarchie AS (
  -- Base : les subordonnés directs d'Alice
  SELECT emp_id, nom, manager_id
  FROM employes
  WHERE manager_id = 1

  UNION ALL

  -- Récursivité : les subordonnés de ceux déjà trouvés
  SELECT e.emp_id, e.nom, e.manager_id
  FROM employes e
  JOIN hierarchie h ON e.manager_id = h.emp_id
)
SELECT * FROM hierarchie;

👀 → Retourne tous les descendants directs et indirects d’Alice (emp_id = 1)


⚠ PiĂšges frĂ©quents
#

ErreurCauseSolution
CTE non utilisĂ©etu as oubliĂ© de l’appeler ensuiteVĂ©rifie que tu appelles bien l’alias
Pas de récursivitétu as oublié RECURSIVEAjoute WITH RECURSIVE ...
RĂ©cursion infiniepas de condition d’arrĂȘtAssure-toi que les relations sont finies
Mauvais nommagemĂȘme nom de colonne en base et CTERenomme les colonnes au besoin

đŸ‹ïžâ€â™‚ïž Exercices pratiques
#

Exo 1 – Noms des clients qui ont commandĂ© plus d’un produit
#

Astuce : CTE pour compter, puis filtre

Exo 2 – Liste des clients sans aucune commande
#

Astuce : LEFT JOIN + CTE d’agrĂ©gation

Exo 3 – Liste hiĂ©rarchique des subordonnĂ©s de Bob (emp_id = 2)
#

Exo 4 – Pour chaque produit, nombre de clients diffĂ©rents l’ayant commandĂ©
#


🧰 Bonus – Tester tout ça dans DuckDB
#

import duckdb

# Liste des clients qui ont commandé >1 produit
duckdb.sql("""
WITH nb_cmd AS (
  SELECT client_id, COUNT(*) AS n
  FROM commandes
  GROUP BY client_id
)
SELECT c.nom, n
FROM clients c
JOIN nb_cmd ON c.client_id = nb_cmd.client_id
WHERE n > 1;
""").df()

📚 Ressources utiles
#

Thibault Clément - Intechnia
Auteur
Thibault Clément - Intechnia
Data scientist
SQL - Cet article fait partie d'une série.
Partie 2: Cet article