If Sales Analytics (Chapter 02) taught you to track revenue over time, Finance closes the loop by tracking profit, expense, and budget variance over the same time dimension - but with a critical difference: finance teams almost always need to compare an actual number to a planned number, not just to a prior period. This chapter combines every pattern built so far - running totals, period-over-period comparison, and leaderboard ranking - into the reporting structure finance and FP&A (Financial Planning & Analysis) teams present to leadership every month.
A typical finance reporting schema centers on a ledger of actuals, often paired with a budget table:
financial_transactions (transaction_id, department_id FK, transaction_date, amount, transaction_type)
transaction_type distinguishes revenue, expense, etc.departments (department_id, department_name)budgets (budget_id, department_id FK, budget_month, budgeted_amount, budget_type)FP&A teams consume this data primarily through monthly rollups, running (year-to-date) totals, and variance against budget.
Every pattern in this chapter has already been introduced - RANK()/DENSE_RANK() for leaderboards (Chapters 01-03), running totals for year-to-date profit (Chapter 02’s running revenue, Chapter 04’s running balance), and LAG() for period-over-period comparison (Chapter 02’s MoM/YoY growth). Finance simply layers a budget comparison on top - typically via a join to a budgets table rather than a new window function - which is why this chapter also serves as a review of everything covered so far, applied to the domain where leadership scrutiny is highest.
| Function | Business Explanation |
|---|---|
RANK() / DENSE_RANK() |
Department leaderboards by profit and by expense. |
SUM() OVER (... ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) |
Running (year-to-date) profit, per department and company-wide. |
LAG() |
Month-over-month expense comparison and volatility flagging. |
Window function + join to budgets |
Actual-vs-budget variance reporting. |
profit column derived from revenue - expense rather than a raw transaction amount.LAG() to compute month-over-month expense deltas, then flagging any delta beyond a fixed materiality threshold (a common audit and governance pattern).RANK() vs. DENSE_RANK() choice affects how tied departments appear on a leaderboard shown to executives - a seemingly cosmetic choice with real communication consequences in a board deck.PARTITION BY department_id, fiscal_year) so the running sum does not silently carry over from the prior year’s final balance.budgets table is cheapest when both are pre-aggregated to the same grain (e.g., department + month) before the join, rather than joining at the raw transaction grain and aggregating afterward.actual - budget in one report and budget - actual in another within the same organization, causing sign confusion in board materials - standardize on one convention (typically actual - budget, where positive means over budget for expenses) and document it.LAG() for month-over-month expense comparison without excluding partial months (e.g., the current, still-in-progress month), which artificially inflates or deflates the calculated volatility.SUM(profit) OVER (PARTITION BY department_id, fiscal_year ORDER BY transaction_month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW).actual - budget, and a clear explanation that a positive expense variance is unfavorable while a positive revenue variance is favorable.LAG(expense) OVER (PARTITION BY department_id ORDER BY month) followed by a percentage-change calculation compared against a materiality threshold.RANK() produce a misleading department leaderboard for an executive presentation?” — Expect a discussion of tie-skipping behavior and when DENSE_RANK() or ROW_NUMBER() (with a documented tiebreaker) is more appropriate.SUM() OVER (...)) is identical; only the underlying business metric (profit vs. revenue) and partition grain (department vs. salesperson) differ.Finance is the capstone domain of this module because nearly every pattern introduced in Chapters 01-04 reappears here in service of the metric leadership scrutinizes most closely: profit. Running totals, leaderboards, and period-over-period comparisons combine with budget joins to produce the actual-vs-budget variance reports that drive monthly business reviews - and by this point, you should recognize the underlying SQL pattern before you even finish reading the business question.
LAG() volatility flag to see which signal catches issues earlier.Next: 05_FINANCE.sql — the fully engineered SQL chapter for this domain, and the final chapter of Module 08.
Previous: 04_BANKING.md · Module: README · Next module: 09_Date_Functions ➡