En ingénierie de données, l'aiguillage logique est omniprésent : déclencher un recalcul uniquement si de nouvelles données sont arrivées, catégoriser des clients selon leur volume d'achat, ou interrompre un script en cas d'incohérence.
Il convient de distinguer deux notions souvent confondues :
1. L'expression déclarative CASE WHEN (utilisable partout dans le SQL standard).
2. L'instruction de contrôle procédurale IF ... THEN ... ELSE (exclusive aux blocs PL/pgSQL).
1. L'expression déclarative : CASE WHEN#
L'expression CASE WHEN évalue une liste de conditions et retourne une valeur unique. Elle s'intègre directement dans les requêtes SELECT, WHERE, ORDER BY ou UPDATE.
Syntaxe générale (Forme recherchée)#
Cas d'usage A : Segmentation et scoring métier#
SELECT
id_client,
nom,
total_achats,
CASE
WHEN total_achats >= 50000 THEN 'Client VIP (HVC)'
WHEN total_achats >= 10000 THEN 'Client Régulier (MVC)'
WHEN total_achats > 0 THEN 'Client Occasionnel (LVC)'
ELSE 'Inactif'
END AS segment_client
FROM analytics.dim_clients;
Cas d'usage B : Agrégation conditionnelle (Pivot Table en SQL pur)#
L'association de SUM() et de CASE WHEN permet de transformer les lignes d'une catégorie en colonnes sans fonction de pivot dédiée :
SELECT
date_vente,
SUM(CASE WHEN categorie = 'Informatique' THEN montant ELSE 0 END) AS ca_informatique,
SUM(CASE WHEN categorie = 'Mobilier' THEN montant ELSE 0 END) AS ca_mobilier,
SUM(CASE WHEN categorie = 'Fournitures' THEN montant ELSE 0 END) AS ca_fournitures,
SUM(montant) AS ca_total
FROM fct_ventes
GROUP BY date_vente
ORDER BY date_vente DESC;
2. L'instruction de contrôle procédurale : IF ... THEN ... ELSE#
À la différence de CASE WHEN qui calcule une valeur, l'instruction IF en PL/pgSQL gouverne quelles actions exécuter.
[ Condition booléenne ]
│
┌─────────────┴─────────────┐
VRAI │ FAUX │
▼ ▼
[ Bloc THEN ] [ Bloc ELSIF ou ELSE ]
│ │
└─────────────┬─────────────┘
▼
[ END IF; ]
[!WARNING] En PL/pgSQL, la syntaxe pour les branches intermédiaires s'écrit obligatoirement
ELSIFouELSEIF(avec unS). La syntaxe Pythonelifprovoquera une erreur de syntaxe à la compilation. Tout bloc conditionnel doit obligatoirement se refermer parEND IF;.
3. Les formes de structures procédurales#
Forme 1 : Condition simple (IF ... THEN ... END IF;)#
DO
$$
DECLARE
v_nb_erreurs INTEGER := 0;
BEGIN
SELECT COUNT(*) INTO v_nb_erreurs FROM logs_anomalies WHERE resolu = FALSE;
IF v_nb_erreurs > 0 THEN
RAISE WARNING 'Attention : % anomalie(s) non résolue(s) détectée(s) !', v_nb_erreurs;
END IF;
END;
$$ LANGUAGE plpgsql;
Forme 2 : Alternative binaire (IF ... THEN ... ELSE ... END IF;)#
DO
$$
DECLARE
v_statut_serveur TEXT := 'PRODUCTION';
BEGIN
IF v_statut_serveur = 'PRODUCTION' THEN
RAISE NOTICE 'Mode sécurisé actif : journalisation stricte.';
ELSE
RAISE NOTICE 'Mode bac à sable : réinitialisation autorisée.';
END IF;
END;
$$ LANGUAGE plpgsql;
Forme 3 : Multi-branches (IF ... ELSIF ... ELSE ... END IF;)#
DO
$$
DECLARE
v_taux_remise NUMERIC(4, 2);
v_anciennete_annees INTEGER := 4;
BEGIN
IF v_anciennete_annees >= 5 THEN
v_taux_remise := 0.20;
ELSIF v_anciennete_annees >= 2 THEN
v_taux_remise := 0.10;
ELSIF v_anciennete_annees >= 1 THEN
v_taux_remise := 0.05;
ELSE
v_taux_remise := 0.00;
END IF;
RAISE NOTICE 'Remise accordée : % %', v_taux_remise * 100, '%';
END;
$$ LANGUAGE plpgsql;
4. Cas d'application en Data Engineering : Contrôle qualité d'ingestion#
Dans un pipeline de données, avant de charger une table de reporting finale, on effectue des contrôles préalables de volumétrie et de cohérence :
DO
$$
DECLARE
v_nb_lignes INTEGER;
c_seuil_minimal CONSTANT INTEGER := 1000;
BEGIN
-- 1. Comptage des données reçues dans la table de staging
SELECT COUNT(*) INTO v_nb_lignes FROM staging.commandes_brutes;
-- 2. Évaluation de la complétude
IF v_nb_lignes = 0 THEN
RAISE EXCEPTION 'ÉCHEC PIPELINE : La table staging est vide ! Abandon immédiat.';
ELSIF v_nb_lignes < c_seuil_minimal THEN
RAISE WARNING 'ALERTE : Seulement % lignes reçues (attendu : au moins %). Chargement sous surveillance.',
v_nb_lignes, c_seuil_minimal;
-- Déclenchement de la procédure de chargement avec marquage
PERFORM etl.charger_avec_reserve();
ELSE
RAISE NOTICE 'SUCCESS : % enregistrements prêts. Lancement de la consolidation.', v_nb_lignes;
PERFORM etl.charger_table_finale();
END IF;
END;
$$ LANGUAGE plpgsql;
5. Mise en pratique : Détecteur et nettoyeur de doublons#
Objectif#
Écrire un bloc anonyme PL/pgSQL qui :
1. Compte le nombre d'adresses email dupliquées dans une table temporaire tmp_prospects.
2. Si des doublons sont présents, journalise un avertissement avec le nombre de doublons trouvés, puis purge les doublons en ne conservant que l'entrée ayant l'identifiant le plus récent.
3. Si aucun doublon n'existe, valide le bon état de la table.
DO
$$
DECLARE
v_doublons_count INTEGER;
BEGIN
-- Comptage des doublons sur le champ email
SELECT COUNT(*)
INTO v_doublons_count
FROM (
SELECT email
FROM tmp_prospects
GROUP BY email
HAVING COUNT(*) > 1
) sub;
IF v_doublons_count > 0 THEN
RAISE WARNING 'DOUBLONS DÉTECTÉS : % emails en double identifiés.', v_doublons_count;
-- Déduplication propre : suppression des doublons anciens
DELETE FROM tmp_prospects
WHERE id NOT IN (
SELECT MAX(id)
FROM tmp_prospects
GROUP BY email
);
RAISE NOTICE 'NETTOYAGE EFFECTUÉ : Table assainie avec succès.';
ELSE
RAISE NOTICE 'CONTRÔLE VALIDÉ : Aucun doublon dans la table des prospects.';
END IF;
END;
$$ LANGUAGE plpgsql;
Grâce aux conditions, vos scripts prennent des décisions autonomes et sécurisent vos données. Dans la leçon suivante, nous aborderons les Structures Répétitives (Boucles LOOP, WHILE et FOR) pour automatiser les traitements itératifs.
Commentaires