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 · key | customer_keyinteger | product_keyinteger | quantityinteger | salesreal | order_datetext |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 2 | 24 | 2025-01-01 |
| 2 | 2 | 3 | 1 | 80 | 2025-01-02 |
| 3 | 1 | 2 | 1 | 45 | 2025-01-15 |
| 4 | 3 | 4 | 2 | 240 | 2025-02-01 |
| 5 | 4 | 3 | 2 | 160 | 2025-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.
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.
Establish monthly grain. The window should operate on these three monthly rows.
step-1.sqlSELECT strftime('%Y-%m',order_date) AS month,SUM(sales) AS sales FROM fact_sales GROUP BY month ORDER BY month;Accumulate revenue. An explicit ROWS frame includes all observed prior months.
step-2.sqlWITH 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 monthCompare prior observations. LAG returns NULL for the first month.
step-3.sqlWITH 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