Analytics2026-07-21

SQL Query for Month-over-Month Growth Rate (MySQL & PostgreSQL)

Write a SQL query to calculate month-over-month growth rate using window functions. Includes LAG(), CTE approach, and handling NULL months.

The Problem

You have a revenue or users table with daily/monthly data, and you need to calculate the percentage change from one month to the next. This is one of the most common analytics queries — and one that trips people up with date truncation and NULL handling.

MySQL Solution (using LAG window function)

WITH monthly AS (SELECT DATE_FORMAT(created_at, '%Y-%m-01') AS month, SUM(amount) AS revenue FROM orders GROUP BY 1) SELECT month, revenue, LAG(revenue) OVER (ORDER BY month) AS prev_revenue, ROUND((revenue - LAG(revenue) OVER (ORDER BY month)) / LAG(revenue) OVER (ORDER BY month) * 100, 2) AS growth_pct FROM monthly;

PostgreSQL Solution (using DATE_TRUNC)

WITH monthly AS (SELECT DATE_TRUNC('month', created_at) AS month, SUM(amount) AS revenue FROM orders GROUP BY 1) SELECT month, revenue, LAG(revenue) OVER (ORDER BY month) AS prev_revenue, ROUND((revenue - LAG(revenue) OVER (ORDER BY month)) / NULLIF(LAG(revenue) OVER (ORDER BY month), 0) * 100, 2) AS growth_pct FROM monthly;

Key Differences

MySQL uses DATE_FORMAT for month truncation; PostgreSQL uses DATE_TRUNC. PostgreSQL needs NULLIF to avoid division by zero. MySQL 8.0+ supports window functions; older versions need a self-join approach.

Try It Yourself

Use our free SQL generator — just type "calculate month over month growth rate from an orders table" and select your dialect.