runtime
75 / 88

lesson 75 Warehouse & reporting projects · advanced

Customer & product reporting contracts

Produce customer and product reports at a defined level of detail.

the idea

A reusable report combines identity, totals, dates, and meaningful segmentation at one entity grain. Preserve entities with no sales when requested. These exercises define recency against 2025-04-01 rather than today, so the answer is reproducible.

tables in this lesson

The challenges use this data. Each column shows its type underneath; → marks a link to another table.

dim_customer4 columns · 5 rows
customer_keyinteger · keycustomer_idtextnametextcountrytext
1C001Alice NguyenUnited States
2C002BenUnited Kingdom
3C003CaraUnited Kingdom
4C004DevIndia
5C005ElenaCanada

all 5 rows

fact_sales6 columns · 9 rows
sale_keyinteger · keycustomer_keyintegerproduct_keyintegerquantityintegersalesrealorder_datetext
1112242025-01-01
2231802025-01-02
3121452025-01-15
43422402025-02-01
54321602025-02-05

showing 5 of 9 rows

dim_product5 columns · 4 rows
product_keyinteger · keyproduct_idtextnametextcategorytextpricereal
1P01NotebookStationery12
2P02Desk lampHome45
3P03KeyboardTech80
4P04HeadphonesTech120

all 4 rows

example

The idea in one query. Press Run to see what it returns; running examples never affects your progress.

example.sql
SELECT
  c.customer_id,
  c.name,
  COUNT(f.sale_key) AS sales_lines,
  COALESCE(SUM(f.sales),0) AS total_sales
FROM dim_customer c
LEFT JOIN fact_sales f ON f.customer_key=c.customer_key
GROUP BY c.customer_key,c.customer_id,c.name;

Watch for: These are report contracts, not inferred customer lifetime value. Segmentation thresholds are exercise-specific.

build it step by step

Each step changes one thing. Run them in order and watch the result change.

  1. Start from the customer. Customers with no sales still belong on this report. The sales table alone cannot list them.

    step-1.sql
    SELECT customer_key, customer_id, name
    FROM dim_customer;
  2. Run the reference. A reusable report combines identity, totals, dates, and meaningful segmentation at one entity grain. Preserve entities with no sales when requested. These exercises define recency against 2025-04-01 rather than today, so the answer is reproducible.

    step-2.sql
    SELECT
      c.customer_id,
      c.name,
      COUNT(f.sale_key) AS sales_lines,
      COALESCE(SUM(f.sales),0) AS total_sales
    FROM dim_customer c
    LEFT JOIN fact_sales f ON f.customer_key=c.customer_key
    GROUP BY c.customer_key,c.customer_id,c.name;

challenge 1

Return customer_id,name,sales_lines,total_sales,recency_days for every dim_customer. Missing sales total=0; recency=NULL with no sales. Recency = days from last order_date to 2025-04-01, integer.

Return customer_idnamesales_linestotal_salesrecency_daysany row order

challenge-1.sql
 
To master this lesson, solve both challenges without hints and pass the concept check. 3 of 3 to go.