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-16
3 min read

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

sqlanalyticstime-serieswindow-functionsreporting

If you work with data, you work with time. Sales happen over time. Users sign up over time. Servers crash over time.

But raw time-series data is often messy and noisy. A daily sales chart might look like a jagged mountain range. To spot the real trends, you need to smooth it out. Today, we'll build a complete analytics report using SQL.

Time series chart with moving average and growth indicators
Time series chart with moving average and growth indicators

1. The 7-Day Moving Average

Why use a moving average? Because Monday sales might always be low and Friday sales high. Looking at a single day is misleading. A Rolling 7-Day Average smooths out these weekly fluctuations.

We use Window Functions for this:

AVG(sales) OVER (
  ORDER BY date 
  ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
)

2. Month-over-Month (MoM) Growth

Growth is the heartbeat of a startup. To calculate it, we need to compare this month's value with last month's value.

We use the LAG() function to look backwards:

LAG(revenue, 1) OVER (ORDER BY month) as previous_month_revenue

Interactive Demo: Analytics Dashboard

Let's combine these concepts. We have a daily_signups table interactively generated below. We will calculate a rolling average and growth rate.

Interactive SQL
Loading...

Handling Missing Dates

Real data often has holes. No sales on Christmas? The row just doesn't exist. This breaks moving average calculations (since "3 rows back" might mean 3 weeks back, not 3 days).

The solution is to Gap Fill using a Recursive CTE (which we covered in another article!).

  1. Generate a series of all dates.
  2. LEFT JOIN your actual data to this series.
  3. Use COALESCE(sales, 0) to turn NULLs into zeros.

Conclusion

SQL isn't just for fetching data; it's for analyzing it. By pushing calculations like Moving Averages and Growth Rates into the database layer, you make your reporting faster and your application code cleaner.

Share this article:

Related Articles

sqlanalytics

SQL for Data Analysis: The Ultimate Guide

Move beyond basic SELECTs. Master the core SQL techniques for real-world data analysis: Data Cleaning, Time-Series Analysis, Window Functions, and Cohort Analysis.

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
sqlanalytics

Calculating Weighted Averages in SQL

Standard averages can be misleading. Learn how to calculate weighted averages in SQL to get more accurate insights from your data.

Read more
Previous

Working with JSON in SQL: NoSQL Powers in a Relational World

Next

SQL Data Types Deep Dive: Picking the Perfect Format for Every Column

Comments

© 2026 SQL Playground. Built for developers.

PrivacyTermsAboutRSS Feed