CASE WHEN ... THEN ... END en SQLL'agrégation conditionnelle en SQL permet de calculer plusieurs métriques dans une seule requête, sans lancer plusieurs requêtes séparées. L'idée est simple : utiliser CASE à l'intérieur d'une fonction d'agrégation (SUM, COUNT, AVG) afin d'inclure seulement les lignes qui correspondent à une condition.
Cette approche est particulièrement utile pour les rapports, les tableaux de bord et l'analytique, quand il faut obtenir plusieurs indicateurs à la fois : volumes, montants, parts, répartitions par statut, etc.
Dans cette leçon, nous allons voir :
CASE.Modèle classique d'agrégation conditionnelle :
SUM(CASE WHEN condition THEN value ELSE 0 END)
ou pour compter des lignes :
SUM(CASE WHEN condition THEN 1 ELSE 0 END)
Ce qui se passe :
CASE renvoie une valeur uniquement pour les lignes qui correspondent ;SELECT
customer_id,
SUM(CASE WHEN amount < 2 THEN 1 ELSE 0 END) AS low_payments,
SUM(CASE WHEN amount BETWEEN 2 AND 6 THEN 1 ELSE 0 END) AS medium_payments,
SUM(CASE WHEN amount > 6 THEN 1 ELSE 0 END) AS high_payments
FROM payment
GROUP BY customer_id
LIMIT 20;
Résultat : pour chaque client, la requête renvoie le nombre de paiements faibles, moyens et élevés.
SELECT
staff_id,
SUM(CASE WHEN amount < 2 THEN amount ELSE 0 END) AS low_amount_total,
SUM(CASE WHEN amount BETWEEN 2 AND 6 THEN amount ELSE 0 END) AS medium_amount_total,
SUM(CASE WHEN amount > 6 THEN amount ELSE 0 END) AS high_amount_total
FROM payment
GROUP BY staff_id;
Résultat : une seule requête renvoie trois totaux différents par employé.
COUNT()Les comptages conditionnels peuvent aussi se faire avec COUNT, pas seulement avec SUM(...1/0...) :
COUNT(CASE WHEN condition THEN 1 END)
Cette forme est également valide, car COUNT ne compte que les valeurs non-NULL.
SELECT
staff_id,
COUNT(CASE WHEN return_date IS NULL THEN 1 END) AS not_returned_count,
COUNT(CASE WHEN return_date IS NOT NULL THEN 1 END) AS returned_count
FROM rental
GROUP BY staff_id;
CASEUn pivot transforme des lignes en colonnes. Les données sources stockent souvent les catégories dans des lignes, alors qu'un rapport attend ces catégories sous forme de colonnes distinctes.
Certaines bases de données proposent un opérateur PIVOT, mais la méthode la plus universelle et portable reste l'agrégation conditionnelle avec CASE.
SELECT
group_column,
SUM(CASE WHEN pivot_key = 'A' THEN measure ELSE 0 END) AS col_a,
SUM(CASE WHEN pivot_key = 'B' THEN measure ELSE 0 END) AS col_b,
SUM(CASE WHEN pivot_key = 'C' THEN measure ELSE 0 END) AS col_c
FROM source_table
GROUP BY group_column;
Dans l'exemple ci-dessous, pour chaque catégorie de films, on compte le nombre de films par classification dans des colonnes séparées :
SELECT
c.name AS category,
SUM(CASE WHEN f.rating = 'G' THEN 1 ELSE 0 END) AS rating_g,
SUM(CASE WHEN f.rating = 'PG' THEN 1 ELSE 0 END) AS rating_pg,
SUM(CASE WHEN f.rating = 'PG-13' THEN 1 ELSE 0 END) AS rating_pg13,
SUM(CASE WHEN f.rating = 'R' THEN 1 ELSE 0 END) AS rating_r,
SUM(CASE WHEN f.rating = 'NC-17' THEN 1 ELSE 0 END) AS rating_nc17
FROM film f
JOIN film_category fc ON f.film_id = fc.film_id
JOIN category c ON fc.category_id = c.category_id
GROUP BY c.name
ORDER BY c.name;
Résultat : chaque ligne correspond à une catégorie, et les colonnes rating_* montrent la répartition des films par classification.
ELSE 0 dans les agrégations numériques pour éviter des NULL inattendus.*_count, *_total).CASE ne se recouvrent pas quand les catégories doivent être exclusives.LIMIT.Rapport de paiements dans une seule requête :
SELECT
staff_id,
COUNT(*) AS payments_total,
SUM(amount) AS amount_total,
SUM(CASE WHEN amount >= 5 THEN 1 ELSE 0 END) AS big_payment_count,
SUM(CASE WHEN amount >= 5 THEN amount ELSE 0 END) AS big_payment_total
FROM payment
GROUP BY staff_id;
Pivot par jour de semaine (idée) :
compter les commandes par jour de semaine dans des colonnes séparées via SUM(CASE WHEN weekday = ... THEN 1 ELSE 0 END).
Calcul de part conditionnelle :
SELECT
customer_id,
SUM(CASE WHEN amount >= 5 THEN 1 ELSE 0 END) * 1.0 / COUNT(*) AS high_payment_share
FROM payment
GROUP BY customer_id;
CASE.SUM(CASE ...) et COUNT(CASE ...), on calcule plusieurs métriques dans une seule requête.CASE est une technique universelle pour transformer des lignes en colonnes.En maîtrisant l'agrégation conditionnelle, vous pourrez écrire des requêtes SQL plus compactes et plus expressives pour l'analyse métier.