Question presented to candidate: "Finance wants a report: for each month, revenue, the change versus the previous month as a percentage, and the change versus the same month last year. How would you write that in SQL, and what can go wrong with the numbers?"
What a strong answer should cover:
- The formula: growth % = (current - previous) / previous Γ 100, with
NULLIF(previous, 0)so a zero base gives NULL instead of an error - Month over month with
LAG(revenue) OVER (ORDER BY month): the previous row, computed in a CTE, then the arithmetic in the outer query - Year over year either with
LAG(revenue, 12)(only safe when every month has a row) or, more robustly, a self join on "same month, previous year" - Missing months:
LAGreturns the previous row, not the previous calendar month; fill a calendar (generate_seriesin PostgreSQL, a recursive CTE elsewhere) or check that the months are adjacent - Arithmetic traps: integer division truncates (
100 * 8000 / 104000is 7), PostgreSQL raisesdivision by zerowhile SQLite returns NULL, and the first period has no base (NULL, not 0 %)
Clarifying questions expected:
- Is the data already one row per month, or do I aggregate from raw orders (and in which time zone are the dates)?
- What should a month with no sales show: 0 revenue, or no row?
- Should a partial current month be compared with a full previous month?
Code / implementation expected: Yes β a LAG-based month-over-month query and a year-over-year comparison, with the division made safe.
Schema used by the examples: