SQL Playground
TutorialsPlayground
SQL FormatterSQL MinifierSyntax ValidatorJSON to SQLCSV to SQLSQL to JSONER Diagram Generator
Daily ChallengeInterviewsCheat SheetBlog

© 2026 SQL Playground. Built for developers.

PrivacyTermsAboutRSS Feed
SQL Playground
TutorialsPlayground
SQL FormatterSQL MinifierSyntax ValidatorJSON to SQLCSV to SQLSQL to JSONER Diagram Generator
Daily ChallengeInterviewsCheat SheetBlog
Back to Blog
2026-01-09
3 min read

Mastering Slowly Changing Dimensions (SCD Type 2) in SQL

sqldata-engineeringetlscddata-warehouse

In a standard database, if a user changes their address, you simply UPDATE the row.

UPDATE users SET city = 'New York' WHERE id = 1;

The old address is gone forever. For a transactional app, this is fine. For data analysis, it's a disaster.

What if you need to know where the user lived last year to calculate shipping costs for an old order?

This is where Slowly Changing Dimensions (SCD) come in. Specifically, Type 2, which is the gold standard for tracking history.

SCD Type 2 timeline showing old and current records with start and end dates
SCD Type 2 timeline showing old and current records with start and end dates

The Logic: Start Date, End Date, and Flags

Instead of overwriting the row, we:

  1. Expire the old row (set an end_date).
  2. Insert a new row with the new data (and a start_date of today).

A table with SCD Type 2 looks like this:

User IDCityStart DateEnd DateIs Current?
1San Francisco2023-01-012024-06-01false
1New York2024-06-02NULLtrue

Implementing the Update Query

Updating an SCD Type 2 table involves two steps (often wrapped in a transaction):

Step 1: Close the old record

We find the current active record for the user and set its end_date to yesterday (or today).

UPDATE user_dim
SET 
    end_date = CURRENT_DATE,
    is_current = false
WHERE user_id = 1 
  AND is_current = true;

Step 2: Insert the new record

We insert the new state, with start_date as today and end_date as NULL (or a future date like 9999-12-31).

INSERT INTO user_dim (user_id, city, start_date, end_date, is_current)
VALUES (1, 'New York', CURRENT_DATE, NULL, true);

Interactive Using Playground

Let's simulate an address change for a user. We'll start with their original record, then "move" them to a new city while keeping the history.

Interactive SQL
Loading...

Querying Point-In-Time Data

The beauty of SCD Type 2 is that you can query the state of the world as it was at any point in time.

To find where Customer 101 lived on Christmas 2023:

SELECT city 
FROM customer_history
WHERE customer_id = 101
  AND '2023-12-25' BETWEEN start_date AND COALESCE(end_date, '9999-12-31');

Conclusion

SCD Type 2 transforms your database from a snapshot of "Now" into a time machine. While it adds complexity to your writes, the ability to reconstruct history is invaluable for accurate reporting and analytics.

Share this article:

Related Articles

sqletl

Removing Duplicate Rows in SQL: A Complete Guide

Duplicate data is a common headache. Learn multiple strategies to identify and remove duplicates in SQL, from simple DISTINCT to advanced ROW_NUMBER techniques.

Read more
sqldata-warehouse

Mastering ROLLUP, CUBE, and GROUPING SETS in SQL

Stop running multiple queries for subtotals. Learn how to use advanced GROUP BY extensions to generate powerful reports in a single pass.

Read more
sqletl

Data Cleaning with SQL: From Messy to Masterpiece

Real-world data is dirty. Master 4 essential SQL functions to clean strings, handle NULLs, and fix formatting errors.

Read more
Previous

Data Masking and Anonymization Techniques in SQL

Next

Geospatial Analysis: Calculating Distances in SQL

Comments

© 2026 SQL Playground. Built for developers.

PrivacyTermsAboutRSS Feed