SQL Playground
TutorialsPlayground
SQL FormatterSQL MinifierSyntax ValidatorJSON to SQLCSV to SQLSQL to JSONER Diagram Generator
Daily ChallengeInterviewsCheat SheetBlog

© 2026 SQL Playground. Built for developers.

PrivacyTermsAboutRSS Feed
SQL Playground
TutorialsPlayground
SQL FormatterSQL MinifierSyntax ValidatorJSON to SQLCSV to SQLSQL to JSONER Diagram Generator
Daily ChallengeInterviewsCheat SheetBlog
Back to Blog
2025-12-25
3 min read

Year-over-Year Growth Analysis in SQL

sqltutorialtime-serieswindow-functionsgrowth-analysis

"How much did we grow compared to last year?"

This is one of the most common questions in business intelligence. To answer it, you need to access data from the previous row while looking at the current row.

Enter LAG(), the time-traveler of SQL functions.

The LAG() Function

LAG() lets you peek at a previous row.

LAG(column_name, offset, default_value) OVER (ORDER BY sort_column)
  • column_name: The value you want to retrieve (e.g., revenue).
  • offset: How many rows back? (Default is 1).
  • default_value: What to return if there is no previous row? (Default is NULL).

Scenario: Annual Revenue Growth

Let's say we have a table of yearly revenue. We want to calculate:

  1. Previous Year's Revenue
  2. Growth Amount (Current - Previous)
  3. Growth Percentage ((Current - Previous) / Previous * 100)

1. The Raw Data

Interactive SQL
Loading...

2. The Growth Calculation

Now, let's use LAG() to bring the 2020 revenue onto the 2021 row.

Interactive SQL
Loading...

Analysis:

  • 2020: prev_year_revenue is NULL because there is no 2019 data. Consequently, growth is NULL.
  • 2021: Grew from 100k to 120k. +20,000 (+20%).
  • 2022: Dropped from 120k to 110k. -10,000 (-8.33%).

Handling NULLs with Default Values

If you want the first year to show 0 growth instead of NULL, you can set a default value in LAG (like 0), or handle the NULL result in your math. However, showing NULL for the first period is usually mathematically correct (growth is undefined without a baseline).

Month-over-Month (MoM)

The same logic applies to months!

LAG(revenue) OVER (ORDER BY year, month)

Just ensure your data has one row per month. If you have missing months (gaps), comparing Row N to Row N-1 might compare March to January! Correcting for gaps typically involves generating a date series (using a recursive CTE) to fill in missing months with 0 before using LAG.

LEAD(): Looking into the Future

The opposite of LAG() is LEAD(). It lets you peek at next year's revenue. This is useful for building models where features include "future target values".

Conclusion

LAG() is indispensable for financial and trend analysis. It turns complex self-joins into simple, readable window functions.

Share this article:

Related Articles

sqltutorial

Calculating Moving Averages and Rolling Windows in SQL

Smooth out noisy data trends using SQL Window Functions. Learn to calculate 7-day and 30-day moving averages with AVG() OVER and ROWS BETWEEN.

Read more
sqlwindow-functions

SQL Window Frames: ROWS vs RANGE

Learn how ROWS and RANGE window frames change results, avoid hidden pitfalls, and build correct moving calculations with clear, runnable examples.

Read more
sqltime-series

Time Series Analysis with SQL: Trends, Growth, and Moving Averages

Turn raw timestamps into business insights. Learn how to calculate Month-over-Month growth and smooth out noisy data with 7-day moving averages.

Read more
Previous

Optimizing Large Dataset Queries: The Pagination Problem

Next

How to Create Pivot Tables in SQL (Without the PIVOT Operator)

Comments

© 2026 SQL Playground. Built for developers.

PrivacyTermsAboutRSS Feed