runtime
76 / 88

lesson 76 Warehouse & reporting projects · advanced

Monthly change & cumulative reports

Measure monthly change and cumulative totals.

the idea

Aggregate to monthly grain before using LAG or a running SUM. A percentage change needs a nonzero prior value. This report uses observed months; a complete calendar would be required if missing months should appear as zero.

tables in this lesson

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

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

example

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

example.sql
WITH monthly AS(
  SELECT strftime('%Y-%m',order_date) AS month, SUM(sales) AS sales
  FROM fact_sales
  GROUP BY month
)
SELECT
  month,
  sales,
  SUM(sales) OVER(ORDER BY month ROWS UNBOUNDED PRECEDING) AS running_sales
FROM monthly;

Watch for: The first month has no prior observation; zero change would misrepresent that absence.

build it step by step

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

  1. Establish monthly grain. The window should operate on these three monthly rows.

    step-1.sql
    SELECT strftime('%Y-%m',order_date) AS month,SUM(sales) AS sales
    FROM fact_sales
    GROUP BY month
    ORDER BY month;
  2. Accumulate revenue. An explicit ROWS frame includes all observed prior months.

    step-2.sql
    WITH monthly AS(
      SELECT strftime('%Y-%m',order_date) AS month,SUM(sales) AS sales
      FROM fact_sales
      GROUP BY month
    )
    SELECT
      month,
      sales,
      SUM(sales) OVER(ORDER BY month ROWS UNBOUNDED PRECEDING) AS running_sales
    FROM monthly
    ORDER BY month
  3. Compare prior observations. LAG returns NULL for the first month.

    step-3.sql
    WITH monthly AS(
      SELECT strftime('%Y-%m',order_date) AS month,SUM(sales) AS sales
      FROM fact_sales
      GROUP BY month
    ),compared AS(
      SELECT *,LAG(sales) OVER(ORDER BY month) AS previous_sales
      FROM monthly
    )
    SELECT
      month,
      sales,
      previous_sales,
      ROUND(100.0*(sales-previous_sales)/NULLIF(previous_sales,0),2) AS change_pct
    FROM compared
    ORDER BY month

challenge 1

Return month (YYYY-MM),sales,running_sales for observed months; cumulative sales ordered by month. Sort output by month.

Return monthsalesrunning_salesrows in the order asked

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