Skip to content
Reliable Data Engineering
Practice problem easy lagwindow-functionstime-series
Solve it in the browser (SQL editor)

Month-over-Month and Year-over-Year Growth

Difficulty: Easy · Topics: lag, window-functions, time-series · Asked at: Google, Netflix, Airbnb

Problem

From daily orders, compute monthly revenue and:

Months with no orders don’t exist in this data. Order by month.

Schema and sample data

CREATE TABLE orders (order_date TEXT, amount INTEGER);
INSERT INTO orders VALUES
('2025-01-15',100),('2025-02-10',120),('2025-03-03',90),
('2026-01-05',150),('2026-01-20',50),('2026-02-14',210),('2026-03-30',180);

Expected output

monthrevenueprev_month_revenuemom_pctyoy_pct
2025-01100NULLNULLNULL
2025-0212010020.0NULL
2025-0390120-25.0NULL
2026-0120090122.2100.0
2026-022102005.075.0
2026-03180210-14.3100.0

Hints

Hint 1

Aggregate to month first: strftime('%Y-%m', order_date).

Hint 2

LAG(revenue, 12) only works if every month exists. Is that true here? Join on the month string instead.

Solution

WITH monthly AS (
  SELECT strftime('%Y-%m', order_date) AS month, SUM(amount) AS revenue
  FROM orders GROUP BY 1
)
SELECT m.month, m.revenue,
       LAG(m.revenue) OVER (ORDER BY m.month) AS prev_month_revenue,
       ROUND(100.0 * (m.revenue - LAG(m.revenue) OVER (ORDER BY m.month))
             / LAG(m.revenue) OVER (ORDER BY m.month), 1) AS mom_pct,
       ROUND(100.0 * (m.revenue - ly.revenue) / ly.revenue, 1) AS yoy_pct
FROM monthly m
LEFT JOIN monthly ly
  ON ly.month = strftime('%Y-%m', DATE(m.month || '-01', '-1 year'))
ORDER BY m.month;

Explanation

Follow-up questions

Make MoM robust to missing months.

Generate a month spine (recursive CTE or calendar table), left join revenue with COALESCE(…, 0), then LAG. Or self-join on month = previous calendar month like the YoY join.