runtime
84 / 88

lesson 84 Warehouse & reporting projects · advanced

Latest-state reporting versus SCD Type 2

Compare current-state reporting with preserved history.

the idea

A latest-state table keeps only the current value of each attribute; a type-2 history keeps every version with a validity interval. Reports about “now” use the current version; reports about the past join each fact to the version valid on its date.

Dataset: Retail

The tables the challenges use, with their first 6 rows. Under each column name: the kind of value it holds, and which table it links to.

customer_history7 columns · 1,685 rows
history_idnumber · unique idcustomer_idnumber · links to customerssegmenttextcountrytextvalid_fromdatevalid_todateis_currentnumber
112347occasionalIceland2010-10-312010-11-010
212347regularIceland2010-11-01NULL1
312353occasionalBahrain2010-10-27NULL1
412359occasionalCyprus2009-12-052010-01-010
512359regularCyprus2010-01-012011-11-010
612359key_accountCyprus2011-11-01NULL1
history_idnumber · unique id
1
customer_idnumber · links to customers
12347
segmenttext
occasional
countrytext
Iceland
valid_fromdate
2010-10-31
valid_todate
2010-11-01
is_currentnumber
0
history_idnumber · unique id
2
customer_idnumber · links to customers
12347
segmenttext
regular
countrytext
Iceland
valid_fromdate
2010-11-01
valid_todate
NULL
is_currentnumber
1
history_idnumber · unique id
3
customer_idnumber · links to customers
12353
segmenttext
occasional
countrytext
Bahrain
valid_fromdate
2010-10-27
valid_todate
NULL
is_currentnumber
1
history_idnumber · unique id
4
customer_idnumber · links to customers
12359
segmenttext
occasional
countrytext
Cyprus
valid_fromdate
2009-12-05
valid_todate
2010-01-01
is_currentnumber
0
history_idnumber · unique id
5
customer_idnumber · links to customers
12359
segmenttext
regular
countrytext
Cyprus
valid_fromdate
2010-01-01
valid_todate
2011-11-01
is_currentnumber
0
history_idnumber · unique id
6
customer_idnumber · links to customers
12359
segmenttext
key_account
countrytext
Cyprus
valid_fromdate
2011-11-01
valid_todate
NULL
is_currentnumber
1

first 6 of 1,685 rows · your queries use all of them

dim_customer5 columns · 848 rows
customer_keynumber · unique idcustomer_idtextcontact_nametextcountrytextregiontext
112347Arthur TurnerIcelandEurope
212353Harry TurnerBahrainRest of World
312359Theo TurnerCyprusEurope
412373Harry HillAustriaEurope
512374Emily HillAustriaEurope
612384Ava MooreSwitzerlandEurope
customer_keynumber · unique id
1
customer_idtext
12347
contact_nametext
Arthur Turner
countrytext
Iceland
regiontext
Europe
customer_keynumber · unique id
2
customer_idtext
12353
contact_nametext
Harry Turner
countrytext
Bahrain
regiontext
Rest of World
customer_keynumber · unique id
3
customer_idtext
12359
contact_nametext
Theo Turner
countrytext
Cyprus
regiontext
Europe
customer_keynumber · unique id
4
customer_idtext
12373
contact_nametext
Harry Hill
countrytext
Austria
regiontext
Europe
customer_keynumber · unique id
5
customer_idtext
12374
contact_nametext
Emily Hill
countrytext
Austria
regiontext
Europe
customer_keynumber · unique id
6
customer_idtext
12384
contact_nametext
Ava Moore
countrytext
Switzerland
regiontext
Europe

first 6 of 848 rows · your queries use all of them

fact_sales7 columns · 45,151 rows
sale_keynumber · unique idorder_idnumbercustomer_keynumber · links to dim_customerproduct_keynumber · links to dim_productorder_datedatequantitynumbersalesdecimal
65625367955620622011-01-04834
6562636795568812011-01-0417.95
6562736795568872011-01-0414.95
6562836795564012011-01-0425.9
65629367955640592011-01-043630.6
65630367955643012011-01-041029.5
sale_keynumber · unique id
65625
order_idnumber
3679
customer_keynumber · links to dim_customer
556
product_keynumber · links to dim_product
2062
order_datedate
2011-01-04
quantitynumber
8
salesdecimal
34
sale_keynumber · unique id
65626
order_idnumber
3679
customer_keynumber · links to dim_customer
556
product_keynumber · links to dim_product
881
order_datedate
2011-01-04
quantitynumber
1
salesdecimal
7.95
sale_keynumber · unique id
65627
order_idnumber
3679
customer_keynumber · links to dim_customer
556
product_keynumber · links to dim_product
887
order_datedate
2011-01-04
quantitynumber
1
salesdecimal
4.95
sale_keynumber · unique id
65628
order_idnumber
3679
customer_keynumber · links to dim_customer
556
product_keynumber · links to dim_product
401
order_datedate
2011-01-04
quantitynumber
2
salesdecimal
5.9
sale_keynumber · unique id
65629
order_idnumber
3679
customer_keynumber · links to dim_customer
556
product_keynumber · links to dim_product
4059
order_datedate
2011-01-04
quantitynumber
36
salesdecimal
30.6
sale_keynumber · unique id
65630
order_idnumber
3679
customer_keynumber · links to dim_customer
556
product_keynumber · links to dim_product
4301
order_datedate
2011-01-04
quantitynumber
10
salesdecimal
29.5

first 6 of 45,151 rows · your queries use all of them

worked example

Run these steps in order to see the idea before you write your own query. The step marked “the pattern” is what the challenges ask for. Running the example does not count toward progress.

  1. Walk one customer’s history intervals. Each row is a type-2 version with valid_from, valid_to, and is_current—half-open intervals avoid double-counting boundary days.the pattern

    example.sql
    SELECT customer_id, segment, country, valid_from, valid_to, is_current
    FROM customer_history
    WHERE customer_id = 12359
    ORDER BY valid_from;
  2. See how many versions customers have. The distribution shows how often segment or country changed—historical reports must join facts to the right version, not every row.

    step-2.sql
    SELECT versions, COUNT(*) AS customers
    FROM (
      SELECT customer_id, COUNT(*) AS versions
      FROM customer_history
      GROUP BY customer_id
    )
    GROUP BY versions;
  3. Pick the version valid on a date. For 2011-06-01 on customer 12359, valid_from <= date and date < valid_to (or NULL end) returns exactly one segment.

    step-3.sql
    SELECT customer_id, segment, valid_from, valid_to
    FROM customer_history
    WHERE customer_id = 12359
      AND valid_from <= '2011-06-01'
      AND (valid_to IS NULL OR '2011-06-01' < valid_to);

common mistake

Joining facts to every history version without a date condition repeats each sale once per version.

challenge 1

Return customer_id, segment and country for the current version of every customer in customer_history.

what to return

Columns
customer_idsegmentcountry in this order
Rows
any order
challenge-1.sql
 
To master this lesson, solve both challenges without hints and pass the concept check. 3 of 3 to go.
Latest-state reporting versus SCD Type 2 — Warehouse & reporting projects · Runtime