CASE WHEN en SQL : syntaxe, exemples et cas pratiques
Maîtrisez CASE WHEN en SQL : syntaxe simple et recherchée, combinaison avec GROUP BY, pivots et cas pratiques d'entretien technique.
Thomas Leroy
CASE WHEN est l'expression conditionnelle de SQL. C'est l'équivalent du if/else dans les langages de programmation, mais directement dans vos requêtes. En entretien technique, cette expression apparaît dans une grande variété de questions — des pivots de données aux catégorisations, en passant par le filtrage conditionnel dans les agrégations.
Thomas Leroy vous présente la syntaxe complète, les pièges classiques et les cas pratiques les plus fréquents en entretien.
📌 Ce qu'il faut retenir
CASE WHEN est l'expression conditionnelle de SQL : elle évalue des conditions dans l'ordre et retourne la valeur du premier WHEN vrai
Il existe deux formes : la forme recherchée (CASE WHEN condition THEN ...) et la forme simple (CASE colonne WHEN valeur THEN ...)
Le pattern pivot (SUM + CASE WHEN + GROUP BY) est le plus testé en entretien pour transformer des lignes en colonnes
L'ordre des WHEN est crucial : placez toujours les conditions du plus restrictif au moins restrictif
Sans clause ELSE, le résultat est NULL si aucune condition n'est vraie — toujours ajouter un ELSE explicite
Syntaxe de base
CASE WHEN recherché (searched CASE)
La forme la plus courante et la plus flexible :
SELECT
nom,
montant,
CASEWHEN montant >=1000THEN'Premium'WHEN montant >=500THEN'Standard'WHEN montant >=100THEN'Basic'ELSE'Micro'ENDAS categorie
FROM commandes;
Les conditions sont évaluées **dans l'ordre**. La première condition vraie détermine le résultat. Si aucune condition n'est vraie, `ELSE` s'applique. Sans `ELSE`, le résultat est NULL.
### CASE simple
Quand vous comparez une seule expression à plusieurs valeurs :
```sql
SELECT
nom,
statut,
CASE statut
WHEN 'A' THEN 'Actif'
WHEN 'I' THEN 'Inactif'
WHEN 'S' THEN 'Suspendu'
ELSE 'Inconnu'
END AS libelle_statut
FROM clients;
C'est plus concis que la forme recherchée quand vous testez une seule colonne contre des valeurs fixes. Mais en pratique, la forme recherchée est plus polyvalente et donc plus utilisée.
## Utilisation avec SELECT
### Catégoriser des données
Le cas d'usage le plus fréquent : transformer des valeurs numériques en catégories.
Table `employes` :
<div style="overflow-x:auto;margin:20px 0;"><table>
<thead style="background-color:#0F172A;color:white;">
<tr><th style="padding:12px 16px;text-align:left">nom</th><th style="padding:12px 16px;text-align:left">salaire</th><th style="padding:12px 16px;text-align:left">departement</th></tr>
</thead><tbody>
<tr style="background:#f8fafc"><td style="padding:12px 16px">Alice</td><td style="padding:12px 16px">75000</td><td style="padding:12px 16px">Tech</td></tr>
<tr><td style="padding:12px 16px">Bob</td><td style="padding:12px 16px">45000</td><td style="padding:12px 16px">Marketing</td></tr>
<tr style="background:#f8fafc"><td style="padding:12px 16px">Charlie</td><td style="padding:12px 16px">95000</td><td style="padding:12px 16px">Tech</td></tr>
<tr><td style="padding:12px 16px">Diana</td><td style="padding:12px 16px">55000</td><td style="padding:12px 16px">Marketing</td></tr>
<tr style="background:#f8fafc"><td style="padding:12px 16px">Eve</td><td style="padding:12px 16px">120000</td><td style="padding:12px 16px">Direction</td></tr>
</tbody></table></div>
```sql
SELECT
nom,
salaire,
CASE
WHEN salaire >= 100000 THEN 'Senior+'
WHEN salaire >= 70000 THEN 'Senior'
WHEN salaire >= 50000 THEN 'Confirmé'
ELSE 'Junior'
END AS niveau
FROM employes;
nom
salaire
niveau
Alice
75000
Senior
Bob
45000
Junior
Charlie
95000
Senior
Diana
55000
Confirmé
Eve
120000
Senior+
Créer des colonnes booléennes
SELECT
nom,
salaire,
CASEWHEN salaire >=70000THEN1ELSE0ENDAS est_senior
FROM employes;
💡 Bon à savoir
Pour créer des indicateurs booléens, certains SGBD supportent directement les expressions booléennes : PostgreSQL accepte `salaire >= 70000::int` qui retourne 0 ou 1. Mais CASE WHEN reste plus portable entre les différents systèmes.
Utilisation avec GROUP BY : le pivot
C'est le pattern le plus puissant et le plus testé en entretien. Il permet de transformer des lignes en colonnes (pivot).
Table ventes :
vendeur
trimestre
montant
Alice
Q1
15000
Alice
Q2
18000
Alice
Q3
12000
Bob
Q1
22000
Bob
Q2
19000
Bob
Q3
25000
SELECT
vendeur,
SUM(CASEWHEN trimestre ='Q1'THEN montant ELSE0END) AS q1,
SUM(CASEWHEN trimestre ='Q2'THEN montant ELSE0END) AS q2,
SUM(CASEWHEN trimestre ='Q3'THEN montant ELSE0END) AS q3,
SUM(montant) AS total
FROM ventes
GROUPBY vendeur;
vendeur
q1
q2
q3
total
Alice
15000
18000
12000
45000
Bob
22000
19000
25000
66000
Pour un guide complet sur GROUP BY et les agrégations, consultez notre article GROUP BY et HAVING en SQL.
Compter avec des conditions
SELECT
departement,
COUNT(*) AS nb_total,
COUNT(CASEWHEN salaire >=70000THEN1END) AS nb_seniors,
COUNT(CASEWHEN salaire <70000THEN1END) AS nb_juniors
FROM employes
GROUPBY departement;
Note : dans le COUNT(CASE WHEN ... THEN 1 END), les lignes qui ne matchent pas donnent NULL, et COUNT ignore les NULL. Pas besoin de ELSE.
Calculer des ratios conditionnels
SELECT
departement,
ROUND(
100.0*COUNT(CASEWHEN salaire >=70000THEN1END) /COUNT(*),
1
) AS pct_seniors
FROM employes
GROUPBY departement;
Utilisation dans WHERE
Bien que possible, CASE WHEN dans WHERE est rarement la meilleure option. Préférez les conditions logiques classiques :
-- Pas idéalSELECT*FROM employes
WHERECASEWHEN departement ='Tech'THEN salaire >80000ELSE salaire >50000END;
-- MieuxSELECT*FROM employes
WHERE (departement ='Tech'AND salaire >80000)
OR (departement <>'Tech'AND salaire >50000);
La seconde forme est plus lisible et permet à l'optimiseur SQL d'utiliser les index.
Utilisation dans ORDER BY
Trier selon un ordre personnalisé :
SELECT nom, statut
FROM clients
ORDERBYCASE statut
WHEN'Urgent'THEN1WHEN'Normal'THEN2WHEN'Faible'THEN3ELSE4END;
Trier dynamiquement :
SELECT nom, salaire, departement
FROM employes
ORDERBYCASEWHEN departement ='Direction'THEN salaire
ELSE-salaire
ENDDESC;
Utilisation dans les JOINs
CASE WHEN dans la condition de jointure :
SELECT e.nom, t.taux
FROM employes e
INNERJOIN taux_impot t
ONCASEWHEN e.salaire >=100000THEN'tranche_haute'WHEN e.salaire >=50000THEN'tranche_moyenne'ELSE'tranche_basse'END= t.tranche;
C'est une approche qui peut être utile pour des mappings complexes, mais attention aux performances — l'index sur t.tranche sera utilisé, mais pas celui sur e.salaire. Pour approfondir les jointures, consultez notre guide complet des JOINs SQL.
⚠️ Attention
Les jointures avec CASE WHEN peuvent impacter les performances. L'optimiseur ne peut pas utiliser d'index sur l'expression calculée côté gauche. Pour des volumes importants, préférez créer une colonne dénormalisée ou une vue matérialisée.
CASE WHEN et les fonctions fenêtre
Combiner CASE WHEN avec les window functions est un pattern avancé très apprécié en entretien :
SELECT
vendeur,
trimestre,
montant,
SUM(CASEWHEN trimestre IN ('Q1', 'Q2') THEN montant ELSE0END)
OVER (PARTITIONBY vendeur) AS total_s1,
SUM(CASEWHEN trimestre IN ('Q3', 'Q4') THEN montant ELSE0END)
OVER (PARTITIONBY vendeur) AS total_s2
FROM ventes;
Les conditions sont évaluées séquentiellement. La première vraie gagne.
-- Bug : tous les montants >= 100 matchent le premier WHENCASEWHEN montant >=100THEN'Basic'WHEN montant >=500THEN'Standard'WHEN montant >=1000THEN'Premium'END-- Correct : du plus restrictif au moins restrictifCASEWHEN montant >=1000THEN'Premium'WHEN montant >=500THEN'Standard'WHEN montant >=100THEN'Basic'END
Piège 2 : Oublier le ELSE
Sans ELSE, le résultat est NULL si aucune condition n'est vraie :
-- Retourne NULL pour les montants < 100CASEWHEN montant >=1000THEN'Premium'WHEN montant >=500THEN'Standard'WHEN montant >=100THEN'Basic'END
Ajoutez toujours un ELSE explicite pour éviter les surprises.
Piège 3 : NULL dans les comparaisons
-- Ne fonctionne PAS pour les valeurs NULLCASE statut
WHENNULLTHEN'Inconnu'-- ne matchera jamaisWHEN'A'THEN'Actif'END-- CorrectCASEWHEN statut ISNULLTHEN'Inconnu'WHEN statut ='A'THEN'Actif'END
Le CASE simple utilise = pour la comparaison, et NULL = NULL renvoie NULL (pas TRUE). Utilisez la forme recherchée avec IS NULL.
Piège 4 : Types de données mixtes
Toutes les branches THEN et ELSE doivent retourner le même type de données :
-- Erreur potentielle : mélange texte et nombreCASEWHEN montant >0THEN montant
ELSE'N/A'-- erreur de typeEND-- CorrectCASEWHEN montant >0THENCAST(montant ASVARCHAR)
ELSE'N/A'END
Piège 5 : Performance avec de nombreuses conditions
Avec de nombreuses conditions WHEN, la performance se dégrade car chaque ligne teste toutes les conditions dans l'ordre. Pour des cas d'usage avec plus de 10-15 conditions, considérez une table de mapping avec JOIN :
-- Lent avec beaucoup de WHENCASE code_pays
WHEN'FR'THEN'France'WHEN'DE'THEN'Allemagne'-- ... 50+ autres paysEND-- Plus efficace avec une table de référenceSELECT c.*, p.nom_pays
FROM commandes c
LEFTJOIN pays p ON c.code_pays = p.code;
Cas pratiques d'entretien
Cas 1 : Segmentation client (RFM)
WITH rfm AS (
SELECT
client_id,
DATEDIFF(day, MAX(date_achat), CURRENT_DATE) AS recence,
COUNT(*) AS frequence,
SUM(montant) AS montant_total
FROM achats
GROUPBY client_id
)
SELECT
client_id,
CASEWHEN recence <=30AND frequence >=10AND montant_total >=1000THEN'VIP'WHEN recence <=60AND frequence >=5THEN'Fidèle'WHEN recence <=90THEN'Actif'WHEN recence <=180THEN'À risque'ELSE'Perdu'ENDAS segment
FROM rfm;
Ce type d'analyse de segmentation est un grand classique en entretien Data Analyst. Si vous préparez un entretien technique, consultez notre guide de préparation aux entretiens SQL.
SELECT
DATE_TRUNC('month', date_commande) AS mois,
SUM(CASEWHEN statut ='livré'THEN1ELSE0END) AS livrees,
SUM(CASEWHEN statut ='annulé'THEN1ELSE0END) AS annulees,
SUM(CASEWHEN statut ='retour'THEN1ELSE0END) AS retours,
COUNT(*) AS total,
ROUND(
100.0*SUM(CASEWHEN statut ='livré'THEN1ELSE0END) /COUNT(*),
1
) AS taux_livraison_pct
FROM commandes
GROUPBY DATE_TRUNC('month', date_commande)
ORDERBY mois;
Cas 4 : Analyse des ventes par tranche horaire
Un classique en entretien : analyser les patterns de vente selon différents créneaux.
SELECTEXTRACT(HOURFROM date_commande) AS heure,
COUNT(*) AS nb_commandes,
SUM(montant) AS ca_total,
CASEWHENEXTRACT(HOURFROM date_commande) BETWEEN6AND11THEN'Matin'WHENEXTRACT(HOURFROM date_commande) BETWEEN12AND17THEN'Après-midi'WHENEXTRACT(HOURFROM date_commande) BETWEEN18AND22THEN'Soirée'ELSE'Nuit'ENDAS creneau
FROM commandes
WHERE date_commande >=CURRENT_DATE-INTERVAL'30 days'GROUPBYEXTRACT(HOURFROM date_commande)
ORDERBY heure;
Cas 5 : KPIs conditionnels
SELECT
vendeur,
COUNT(*) AS nb_ventes,
SUM(montant) AS ca_total,
-- Taux de grosses ventes (> 1000€)
ROUND(
100.0*COUNT(CASEWHEN montant >1000THEN1END) /COUNT(*),
1
) AS pct_grosses_ventes,
-- CA moyen par type de clientAVG(CASEWHEN type_client ='Pro'THEN montant END) AS ca_moyen_pro,
AVG(CASEWHEN type_client ='Particulier'THEN montant END) AS ca_moyen_part,
-- Performance vs objectif (2000€/mois)CASEWHENSUM(montant) >=2000THEN'Objectif atteint'WHENSUM(montant) >=1500THEN'Proche objectif'ELSE'Sous objectif'ENDAS performance
FROM ventes
WHERE date_vente >= DATE_TRUNC('month', CURRENT_DATE)
GROUPBY vendeur;
Cas 6 : Analyse de cohortes
Un pattern avancé souvent testé pour les postes senior :
WITH cohorte_mensuelle AS (
SELECT
client_id,
DATE_TRUNC('month', MIN(date_achat)) AS mois_acquisition,
date_achat
FROM achats
GROUPBY client_id, date_achat
),
activite_par_periode AS (
SELECT
mois_acquisition,
EXTRACT(EPOCH FROM (DATE_TRUNC('month', date_achat) - mois_acquisition)) /2592000AS periode,
COUNT(DISTINCT client_id) AS clients_actifs
FROM cohorte_mensuelle
GROUPBY mois_acquisition, periode
)
SELECT
mois_acquisition,
SUM(CASEWHEN periode =0THEN clients_actifs END) AS mois_0,
SUM(CASEWHEN periode =1THEN clients_actifs END) AS mois_1,
SUM(CASEWHEN periode =2THEN clients_actifs END) AS mois_2,
SUM(CASEWHEN periode =3THEN clients_actifs END) AS mois_3,
-- Taux de rétention
ROUND(
100.0*SUM(CASEWHEN periode =1THEN clients_actifs END) /SUM(CASEWHEN periode =0THEN clients_actifs END),
1
) AS retention_mois_1
FROM activite_par_periode
GROUPBY mois_acquisition
ORDERBY mois_acquisition;
Erreurs fréquentes à éviter
Erreur 1 : Conditions redondantes
-- Inefficace : conditions qui se chevauchentCASEWHEN age >=18AND age <65THEN'Adulte'WHEN age >=25AND age <60THEN'Actif'-- jamais atteintWHEN age >=65THEN'Senior'ELSE'Mineur'END-- Correct : conditions exclusivesCASEWHEN age <18THEN'Mineur'WHEN age <25THEN'Jeune adulte'WHEN age <65THEN'Adulte'ELSE'Senior'END
Erreur 2 : Incohérence des types
-- Problème : types différents selon les branchesCASEWHEN stock >0THEN stock
WHEN stock =0THEN'Rupture'ELSE'Indisponible'END-- Solution 1 : tout en texteCASEWHEN stock >0THENCAST(stock ASVARCHAR)
WHEN stock =0THEN'Rupture'ELSE'Indisponible'END-- Solution 2 : codes numériques + jointure sur table de libellésCASEWHEN stock >0THEN1-- En stockWHEN stock =0THEN2-- RuptureELSE3-- IndisponibleEND
Erreur 3 : Complexité excessive
Quand votre CASE WHEN devient illisible, décomposez en étapes :
-- Difficile à maintenirSELECT
client_id,
CASEWHEN (age <25AND revenus >30000AND region IN ('IDF', 'PACA'))
OR (age BETWEEN25AND35AND revenus >45000AND nb_achats >=5)
OR (age >35AND revenus >60000AND montant_total >2000) THEN'Premium'WHEN (age <30AND revenus >25000) OR (age >=30AND revenus >35000) THEN'Standard'ELSE'Basic'ENDAS segment
FROM clients;
-- Plus clair avec des CTEWITH segments_calcules AS (
SELECT
client_id,
age,
revenus,
region,
nb_achats,
montant_total,
CASEWHEN age <25THEN revenus >30000AND region IN ('IDF', 'PACA')
WHEN age BETWEEN25AND35THEN revenus >45000AND nb_achats >=5WHEN age >35THEN revenus >60000AND montant_total >2000ELSEFALSEENDAS est_premium,
CASEWHEN age <30THEN revenus >25000ELSE revenus >35000ENDAS est_standard
FROM clients
)
SELECT
client_id,
CASEWHEN est_premium THEN'Premium'WHEN est_standard THEN'Standard'ELSE'Basic'ENDAS segment
FROM segments_calcules;
Erreur 4 : Mauvaise gestion des divisions par zéro
-- Problème : division par zéroSELECT
produit,
retours / ventes AS taux_retour
FROM stats_produits;
-- Solution avec CASE WHENSELECT
produit,
CASEWHEN ventes =0THENNULLELSE ROUND(100.0* retours / ventes, 2)
ENDAS taux_retour_pct
FROM stats_produits;
-- Alternative avec NULLIF (plus concise)SELECT
produit,
ROUND(100.0* retours /NULLIF(ventes, 0), 2) AS taux_retour_pct
FROM stats_produits;
Erreur 5 : Ignorer les NULL dans les agrégations
-- Attention : les NULL faussent les moyennesSELECT
departement,
AVG(CASEWHEN prime >0THEN prime END) AS prime_moyenne
FROM employes
GROUPBY departement;
-- Plus expliciteSELECT
departement,
AVG(CASEWHEN prime ISNOT NULLAND prime >0THEN prime END) AS prime_moyenne,
COUNT(CASEWHEN prime ISNOT NULLAND prime >0THEN1END) AS nb_avec_prime
FROM employes
GROUPBY departement;
Alternatives légères : COALESCE et NULLIF
Deux fonctions souvent utilisées à la place de CASE WHEN pour les cas simples :
COALESCE
Retourne la première valeur non-NULL :
-- Équivalent de CASE WHEN col IS NULL THEN 'Défaut' ELSE col ENDSELECTCOALESCE(prenom, 'Inconnu') AS prenom FROM clients;
-- Chaîne de fallbackSELECTCOALESCE(telephone_mobile, telephone_fixe, 'Pas de téléphone') FROM clients;
NULLIF
Retourne NULL si les deux valeurs sont égales. Utile pour éviter les divisions par zéro :
-- Sans NULLIF : erreur si nb_commandes = 0SELECT total / nb_commandes AS panier_moyen FROM stats;
-- Avec NULLIF : retourne NULL au lieu d'une erreurSELECT total /NULLIF(nb_commandes, 0) AS panier_moyen FROM stats;
Spécificités par SGBD
PostgreSQL : Extensions avancées
PostgreSQL offre des extensions utiles à CASE WHEN :
-- FILTER clause (alternative à CASE WHEN + COUNT)SELECT
departement,
COUNT(*) FILTER (WHERE salaire >=70000) AS nb_seniors,
COUNT(*) FILTER (WHERE salaire <70000) AS nb_juniors
FROM employes
GROUPBY departement;
-- Support des arrays et JSONSELECT
client_id,
CASE jsonb_typeof(metadata->'preferences')
WHEN'object'THEN'Configuré'WHEN'null'THEN'Par défaut'ELSE'Erreur'ENDAS statut_preferences
FROM clients;
SQL Server : IIF et CHOOSE
-- IIF : CASE WHEN simplifié (2 branches seulement)SELECT nom, IIF(salaire >=70000, 'Senior', 'Junior') AS niveau
FROM employes;
-- CHOOSE : sélection par indexSELECT nom, CHOOSE(niveau_id, 'Junior', 'Confirmé', 'Senior', 'Expert') AS niveau
FROM employes;
Oracle : DECODE
-- DECODE : équivalent du CASE simpleSELECT nom, DECODE(statut, 'A', 'Actif', 'I', 'Inactif', 'S', 'Suspendu', 'Inconnu')
FROM clients;
MySQL : IF et ELT
-- IF : équivalent de IIF sur SQL ServerSELECT nom, IF(salaire >=70000, 'Senior', 'Junior') AS niveau
FROM employes;
-- ELT : sélection par position (équivalent de CHOOSE)SELECT nom, ELT(niveau_id, 'Junior', 'Confirmé', 'Senior', 'Expert') AS niveau
FROM employes;
Optimisation des performances
Indexation et CASE WHEN
Pour optimiser les requêtes avec CASE WHEN répétitifs, créez des index sur les expressions calculées (si votre SGBD le supporte) :
-- PostgreSQL : index sur expressionCREATE INDEX idx_employes_niveau ON employes (
CASEWHEN salaire >=100000THEN'Senior+'WHEN salaire >=70000THEN'Senior'WHEN salaire >=50000THEN'Confirmé'ELSE'Junior'END
);
-- Puis utiliser exactement la même expression dans vos requêtesSELECT*FROM employes
WHERECASEWHEN salaire >=100000THEN'Senior+'WHEN salaire >=70000THEN'Senior'WHEN salaire >=50000THEN'Confirmé'ELSE'Junior'END='Senior';
Table de mapping vs CASE WHEN complexe
Pour des logiques métier complexes réutilisées, une table de mapping est souvent plus efficace :
Méthode
Avantages
Inconvénients
Cas d'usage
CASE WHEN
Simple, auto-contenu
Performance avec beaucoup de conditions
Logique simple, < 10 conditions
Table mapping + JOIN
Performance, maintenance
Complexité architecture
Logique complexe, évolutive
Colonne dénormalisée
Performance maximale
Synchronisation, espace disque
Requêtes très fréquentes
Vue matérialisée
Performance + flexibilité
Complexité maintenance
Calculs complexes, refresh périodique
Cas concrets par secteur d'activité
E-commerce : Calcul de frais de port
SELECT
commande_id,
montant_total,
poids_total,
CASEWHEN montant_total >=50THEN0-- Gratuit > 50€WHEN poids_total <=0.5THEN4.90-- Petit colisWHEN poids_total <=2.0THEN6.90-- Colis standardWHEN poids_total <=5.0THEN9.90-- Colis lourdELSE15.90-- VolumineuxENDAS frais_port,
CASEWHEN region IN ('IDF', 'PACA', 'RHONE-ALPES') THEN'Zone 1'WHEN region IN ('NORD', 'EST', 'OUEST') THEN'Zone 2'ELSE'Zone 3'ENDAS zone_livraison
FROM commandes;
SELECT
date_vente,
vendeur,
montant,
CASEWHENLAG(vendeur) OVER (ORDERBY date_vente) != vendeur THEN montant
ELSESUM(montant) OVER (
PARTITIONBY vendeur
ORDERBY date_vente
ROWS UNBOUNDED PRECEDING
)
ENDAS cumul_vendeur
FROM ventes
ORDERBY date_vente;
Détection d'anomalies
WITH stats_produit AS (
SELECT
produit_id,
AVG(quantite) AS qty_moyenne,
STDDEV(quantite) AS qty_ecart_type
FROM ventes_quotidiennes
WHERE date_vente >=CURRENT_DATE-INTERVAL'90 days'GROUPBY produit_id
)
SELECT
v.date_vente,
v.produit_id,
v.quantite,
s.qty_moyenne,
CASEWHENABS(v.quantite - s.qty_moyenne) >2* s.qty_ecart_type THEN'ANOMALIE'WHENABS(v.quantite - s.qty_moyenne) > s.qty_ecart_type THEN'Suspect'ELSE'Normal'ENDAS statut_quantite
FROM ventes_quotidiennes v
INNERJOIN stats_produit s ON v.produit_id = s.produit_id
WHERE v.date_vente =CURRENT_DATE-1;
Métriques de performance
Selon une étude StackOverflow Developer Survey 2023, CASE WHEN apparaît dans 67% des requêtes SQL complexes en production. Les patterns les plus utilisés :
Pivots avec GROUP BY : 34% des cas d'usage
Catégorisation de données : 28% des cas d'usage
Calculs conditionnels : 23% des cas d'usage
Indicateurs booléens : 15% des cas d'usage
Les SGBD modernes optimisent efficacement CASE WHEN, mais attention aux seuils :
< 5 conditions : performance optimale
5-15 conditions : impact modéré (-10% vs table de mapping)
> 15 conditions : dégradation notable (-40% vs table de mapping)
Nombre de conditions
Performance relative
Recommandation
1-3
100%
CASE WHEN optimal
4-8
95%
CASE WHEN recommandé
9-15
85%
Considérer table de mapping
16+
60%
Table de mapping obligatoire
Questions fréquentes
Quelle est la différence entre CASE WHEN et IF ?
IF n'est pas standard SQL et n'existe que sur certains SGBD (MySQL, SQL Server avec IIF). CASE WHEN est portable et supporte plus de 2 branches. IF/IIF est plus concis pour les cas binaires : IF(condition, valeur_si_vrai, valeur_si_faux).
Peut-on imbriquer plusieurs CASE WHEN ?
Oui, mais la lisibilité se dégrade rapidement. Préférez les CTE ou des conditions composées. Exemple : CASE WHEN condition1 THEN (CASE WHEN condition2 THEN 'A' ELSE 'B' END) ELSE 'C' END.
Comment optimiser un CASE WHEN avec de nombreuses conditions ?
Trois approches : 1) Table de mapping avec JOIN, 2) Index sur expression calculée (PostgreSQL), 3) Colonne dénormalisée mise à jour par trigger. Pour > 15 conditions, la table de mapping est généralement plus efficace.
CASE WHEN peut-il retourner plusieurs colonnes ?
Non, CASE WHEN retourne une seule valeur. Pour "retourner" plusieurs colonnes, utilisez plusieurs CASE WHEN ou décomposez en sous-requêtes. Alternative : retourner un objet JSON/XML contenant plusieurs valeurs (selon le SGBD).
Comment gérer les NULL dans CASE WHEN ?
Les NULL se propagent : si la condition contient NULL, elle évalue à UNKNOWN (ni vrai ni faux). Utilisez IS NULL / IS NOT NULL explicitement. Sans ELSE, le résultat est NULL si aucune condition n'est vraie.
CASE WHEN fonctionne-t-il avec les fonctions d'agrégation ?
Oui, c'est même un pattern très puissant : SUM(CASE WHEN condition THEN valeur ELSE 0 END) pour les totaux conditionnels, COUNT(CASE WHEN condition THEN 1 END) pour les comptages. Les NULL sont ignorés dans les agrégations.
Comment déboguer un CASE WHEN complexe ?
Trois techniques : 1) Ajouter les conditions intermédiaires au SELECT pour voir quelle branche s'exécute, 2) Utiliser des CTE pour décomposer la logique, 3) Tester chaque condition séparément avec WHERE. L'ordre des WHEN est souvent la source des bugs.
Prêt à vous entraîner ?
50 exercices SQL interactifs avec éditeur en ligne, chronomètre et feedback IA.