Slowly Changing Dimensions (SCD)
When an attribute changes, what does history say?
SCDs handle dimension attributes that change over time. Type 1 overwrites (no history), Type 2 keeps versioned rows (full history), Type 3 keeps prior/current columns (limited history) — each trades history for complexity.
What you will learn
- Choose SCD type by the business need for history
- Implement SCD-2 with surrogate keys and effective dates
- Avoid the common type-2 traps: grain drift, orphan rows, double-counting
What is this?
Slowly Changing Dimensions handle attributes — like a customer's region or tier — that change occasionally, not per transaction. Type 1 overwrites the attribute, losing the past. Type 2 inserts a new dimension row per version with effective dates and a current flag, preserving full history. Type 3 keeps a current and prior column, preserving only the last change. BI correctness often depends on choosing the right type.
Why do you need it?
- Analysts need to see sales attributed to the customer's region AT THAT TIME, not today's.
- Overwriting (type 1) is tempting for simplicity but silently rewrites history for everyone.
- Type 2 gives full history at the cost of surrogate keys, active flags and grain tests.
- Report behavior changes with the type — the choice shapes daily queries.
Mental model
Updating a band member's bio
SCD types
Type 1: correct the typo, forget the old name. Type 2: keep 'the drummer who joined in 2015' as its own era with start/end dates. Type 3: keep only the previous band member's name in a 'previous keyboardist' column. Each record of history differs — and so does what you can later say.
How it works
- Type 1: UPDATE in place; the old value is gone; history reports change retroactively.
- Type 2: on change, close the current row's effective_to, open a new row with a new surrogate key and active=1.
- Type 3: retain previous value in a column and roll the current one; only last change survives.
- Facts reference the surrogate key of the version active at their event time.
- Invariants: one active row per natural key; contiguous effective dates (no gaps/overlap).
Type 2 versioning through time.
In production
- A telecom models customer plans SCD-2; revenue by plan today vs plan-at-signup both compute correctly.
- An e-commerce company tracks product category changes type 1 (past doesn't matter) and customer tier type 2 (history drives retention analysis).
- A finance dim type 3 for 'previous manager' supports a compare-last-role report.
Best practices
- Ask the question that must survive: 'sales by tier AT sale time' needs type 2; 'fix a typo' needs type 1.
- For type 2 add: surrogate key, business key, effective_from/to, current flag, and tests.
- Close periods to 'end of last month' where reports compare snapshots, to avoid mid-month flips.
- Document the type per attribute — a mixed dimension needs an attention note.
Common mistakes
- Mixing type 1 and 2 by updating rows 'to be safe', losing both history and simplicity.
- Forgetting effective dates align, causing overlapping or gapped history.
- Two active rows per natural key after a partial load breaks every join.
- Reports counting dimension versions instead of fact members.
Common issues
Report shows today's region on last year's ordersFact joined current dim row instead of the version at event time
Join on the surrogate key present in the fact, or use as-of date logic.
Gap in history after a failed loadClose/insert not applied atomically
Wrap the versioning update in a transaction; add contiguity tests.
Debugging tips
- History 'jumps' in reports? Check the SCD type — overwrite (T1) rewrites the past.
- Customer appearing twice in a group-by? Two active SCD-2 rows for one business key.
- Date slices inconsistent? Verify effective_to boundaries and the as-of rule.
Interview checkpoint
Hands-on lab
- Version customer tiers with surrogate keys and effective dates
- Prove old facts keep their event-time tier
- Test the 'one active row' invariant
Implement SCD Type 2 in SQL
45 min · advanced
Quick quiz
Which SCD type preserves full historical versions of an attribute?
Type 1 SCD overwrites the old attribute value, losing history.