Le PIVOT / UNPIVOT est indispensable dès qu’on veut restructurer ses données, par exemple passer de lignes → colonnes (ou l’inverse). C’est l’équivalent SQL des pivot_table() ou melt() de pandas.
🔄 Pourquoi pivoter ?#
- Table longue → table large : voir chaque mois en colonne
- Préparer un jeu de données pour analyse, reporting, visualisation
- Se rapprocher de la structure utilisateur-friendly
📌 PIVOT (lignes → colonnes)#
La syntaxe dépend des SGBD. Voici 2 méthodes :
✅ Méthode 1 –
PIVOTnatif (ex : SQL Server, DuckDB, Oracle)SELECT * FROM ( SELECT client_id, mois, montant FROM ventes ) PIVOT ( SUM(montant) FOR mois IN ('2024-01', '2024-02', '2024-03') );💡 Résultat : 1 ligne par
client_id, avec une colonne par mois.✅ Méthode 2 – via
CASE WHEN(portable, fonctionne partout)SELECT client_id, SUM(CASE WHEN mois = '2024-01' THEN montant END) AS janv, SUM(CASE WHEN mois = '2024-02' THEN montant END) AS fev, SUM(CASE WHEN mois = '2024-03' THEN montant END) AS mars FROM ventes GROUP BY client_id;🔁 Très utile quand
PIVOTn’est pas dispo (comme sur SQLite ou MySQL (?)).
📌 UNPIVOT (colonnes → lignes)#
Moins courant, mais utile pour :
- Transformer une table large (ex : 1 colonne par mois) en longue
- Préparer une table pour des agrégations, ou du machine learning
Voici deux manières :
✅ UNPIVOT explicite (ex : SQL Server, DuckDB)
SELECT * FROM ventes UNPIVOT ( montant FOR mois IN (janv, fev, mars) );✅ UNPIVOT manuel avec
UNION ALL(portable)SELECT client_id, '2024-01' AS mois, janv AS montant FROM ventes UNION ALL SELECT client_id, '2024-02', fev FROM ventes UNION ALL SELECT client_id, '2024-03', mars FROM ventes;
🧯 Pièges à éviter#
| ⚠️ Piège | ✅ Solution |
|---|---|
| Trop de colonnes générées (pivot dynamique) | Filtrer les valeurs ou faire un PIVOT dynamique côté code |
| Valeurs NULL après pivot | Utiliser COALESCE(..., 0) |
Mauvais agrégat (SUM, COUNT, etc.) | Bien préciser dans la clause PIVOT(...) |
🏋️♂️ Exercices#
- Transformer une table de ventes (client_id, mois, montant) pour avoir une colonne par mois
- Revenir à une table longue (client_id, mois, montant) depuis une table avec colonnes
janv,fev,mars - Créer un tableau croisé dynamique produit x mois avec
SUM(montant)en valeur
duckdb.sql("""
SELECT *
FROM (
SELECT client_id, mois, montant
FROM ventes
)
PIVOT (
SUM(montant)
FOR mois IN ('2024-01', '2024-02', '2024-03')
)
""").df()