Slowly Changing Dimensions, types 0 à 3

Résumé

Un attribut de dimension change parfois (un client déménage, un produit change de catégorie). Une Slowly Changing Dimension (SCD) est la technique choisie pour décider quoi faire de l’ancienne valeur. Kimball en décrit plusieurs types. Les types 1 et 2 dominent la pratique ; les types 0 et 3 sont plus rares. Type 0 (garder la valeur d’origine), type 1 (écraser, l’historique est perdu), type 2 (ajouter une ligne, l’historique est complet), type 3 (ajouter une colonne pour garder l’ancienne valeur). Le choix se fait attribut par attribut, selon la question métier : veut-on les faits tels que les décrivait le monde à l’époque, ou tels que le décrit le monde aujourd’hui ?

Prérequis

Table de faits, dimension, clé de substitution : Inmon, Kimball et Data Vault et Glossaire data engineering.

Le cas fil rouge

Le client 42, Dupont, habitait Toulouse. Il déménage à Lyon le 2026-03-01. Il a passé une commande en janvier (150 €) et une en avril (200 €).

Question : le chiffre d’affaires par ville de Dupont, c’est Toulouse 150 € et Lyon 200 €, ou Lyon 350 € ?

La réponse dépend du type de SCD.

Type 0 : conserver l’original

L’attribut ne change jamais, quoi qu’il arrive à la source. D’après Kimball, ce type convient aux attributs libellés « original » (par exemple le score de crédit d’origine d’un client), aux identifiants durables, et à la plupart des attributs d’une dimension de date.1

client_keyclient_idville_origine
142Toulouse

Après le déménagement, la ligne ne bouge pas. Les faits restent groupés par la valeur d’origine.

Type 1 : écraser

La nouvelle valeur remplace l’ancienne dans la même ligne. Le type 1 reflète toujours l’affectation la plus récente et détruit l’historique. Il est simple à mettre en œuvre et ne crée pas de ligne supplémentaire.1

client_keyclient_idville
142Lyon

Les deux commandes sont désormais rattachées à Lyon : 350 €. Conséquence à ne pas oublier : les tables de faits agrégées et les cubes qui dépendent de cet attribut doivent être recalculés.1

Type 2 : ajouter une ligne

Chaque changement crée une nouvelle ligne avec une nouvelle clé de substitution. La clé primaire de la dimension doit donc dépasser la clé naturelle, puisqu’un même client a plusieurs lignes. Kimball demande au minimum trois colonnes supplémentaires : une date d’effet, une date d’expiration et un indicateur de ligne courante.1

client_keyclient_idvillevalid_fromvalid_tois_current
142Toulouse2020-01-012026-02-28faux
242Lyon2026-03-019999-12-31vrai

La table de faits utilise la clé de substitution en vigueur au moment du fait : la commande de janvier pointe vers client_key = 1, celle d’avril vers client_key = 2. Résultat : Toulouse 150 €, Lyon 200 €, l’historique tel qu’il était.

flowchart LR
    F1["Fait : commande de janvier<br/>client_key = 1"] --> D1["Dupont, Toulouse<br/>2020-01-01 → 2026-02-28"]
    F2["Fait : commande d'avril<br/>client_key = 2"] --> D2["Dupont, Lyon<br/>2026-03-01 → courant"]

Une implémentation SQL (BigQuery)

Deux étapes dans une transaction : fermer les lignes courantes dont l’attribut a changé, puis insérer la nouvelle version.

BEGIN TRANSACTION;
 
-- 1. Fermer les lignes courantes dont la ville a changé
--    (valid_to = veille de la nouvelle date d'effet)
UPDATE dim_client AS d
SET valid_to = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY), is_current = FALSE
FROM stg_client AS s
WHERE d.client_id = s.client_id
  AND d.is_current
  AND d.ville IS DISTINCT FROM s.ville;
 
-- 2. Insérer la nouvelle version (client modifié ou nouveau)
INSERT INTO dim_client (client_key, client_id, ville, valid_from, valid_to, is_current)
SELECT GENERATE_UUID(), s.client_id, s.ville,
       CURRENT_DATE(), DATE '9999-12-31', TRUE
FROM stg_client AS s
LEFT JOIN dim_client AS d
  ON d.client_id = s.client_id AND d.is_current
WHERE d.client_id IS NULL;
 
COMMIT TRANSACTION;

Prérequis : stg_client contient une seule ligne par client_id. Avec deux lignes pour un même client, BigQuery refuse l’UPDATE ... FROM (« must match at most one source row »), et l’INSERT créerait deux lignes courantes. Si la source peut en fournir plusieurs, la dédupliquer d’abord, par exemple avec QUALIFY ROW_NUMBER() OVER (PARTITION BY client_id ORDER BY updated_at DESC) = 1.

Après l’étape 1, un client modifié n’a plus de ligne courante : l’étape 2 lui en crée une. Un client jamais vu en reçoit une aussi. Relancer le script sans nouveau changement ne produit aucune ligne : le traitement est idempotent (Idempotence et backfill).

Limites de cette implémentation

Deux changements le même jour donnent une ligne dont valid_to précède valid_from (intervalle vide) : prévoir une granularité plus fine que le jour si cela peut arriver. client_key est un UUID dans le script, alors que les tableaux montrent 1 et 2 pour la lisibilité. Une suppression côté source ne ferme pas la ligne. Enfin, la date de validité est celle du traitement. Ici, valid_from est la date d’exécution du script, pas la date du déménagement. Si la source fournit la date réelle du changement, c’est elle qu’il faut utiliser. Et un changement survenu puis annulé entre deux exécutions n’est jamais vu. C’est la même limite que celle des snapshots dbt : voir dbt et le lakehouse.

Type 3 : ajouter une colonne

La nouvelle valeur écrase l’attribut principal, comme en type 1, et l’ancienne valeur est conservée dans une colonne supplémentaire. Kimball appelle cela une « réalité alternative » : l’utilisateur peut grouper les faits par la valeur courante ou par l’ancienne. La technique est utilisée relativement rarement.1

client_keyclient_idvilleville_precedente
142LyonToulouse

Elle ne garde qu’un seul niveau d’historique : un second déménagement écrase ville_precedente. Elle convient à un changement massif et unique, par exemple une réorganisation commerciale où l’on veut comparer « avant » et « après ».

Choisir

TypeHistoriqueTaille de la dimensionQuand
0Aucun changementStableValeur d’origine, identifiant durable, date
1PerduStableCorrection d’erreur, attribut sans intérêt historique
2CompletCroît avec les changementsLe passé doit rester exact : segment, région, statut
3Un niveauStableComparer « avant » et « après » un changement unique

Règles d'usage

  • Une même dimension mélange des types : date_naissance en type 0, email en type 1, ville en type 2.
  • En cas de doute sur un attribut, la question à poser au métier est « Le rapport d’il y a un an doit-il changer si cet attribut change aujourd’hui ? » Si oui, type 1 ; sinon, type 2.
  • Le type 2 multiplie les lignes : à surveiller sur les attributs qui changent souvent.

Les autres types (4, 5, 6, 7)

Notes liées

Notes de bas de page

  1. Kimball Group, Dimensional Modeling Techniques et les pages type 0, type 1, type 2, type 3, type 4, type 6, type 7, pages officielles lues le 24 octobre 2026. ↩ ↩2 ↩3 ↩4 ↩5 ↩6