SQL Window Functions for Marketing Analysts: Practical Examples and Use Cases

Atticus Li·

SQL Window Functions for Marketing Analysts: Practical Examples and Use Cases

SQL window functions are one of the most powerful tools in a marketing analyst's toolkit—yet many analysts don't use them because they seem intimidating. This guide breaks down window functions through practical marketing examples that you can apply immediately.

Window functions let you perform calculations across rows that are related to the current row, without collapsing the results into a single row like GROUP BY does. Think of them as adding computed columns that reference other rows in your dataset.

Why Marketing Analysts Need Window Functions

  • Calculate running totals of ad spend or revenue over time
  • Rank campaigns by performance within each channel
  • Compare each day's metrics to the previous day (day-over-day changes)
  • Calculate moving averages to smooth out daily fluctuations
  • Find each customer's first and last touchpoint for attribution
  • Identify the top N campaigns by any metric within any grouping
  • Calculate cumulative conversion rates over time

The Basics: How Window Functions Work

Every window function has three parts:

The function: What calculation to perform (SUM, AVG, ROW_NUMBER, RANK, LAG, LEAD, etc.)

PARTITION BY: How to group rows (similar to GROUP BY, but without collapsing rows)

ORDER BY: How to sort rows within each partition

The syntax is: FUNCTION() OVER (PARTITION BY column ORDER BY column)

ROW_NUMBER and RANK: Finding Top Performers

Use Case: Top 3 Campaigns Per Channel

You want to find the top 3 campaigns by revenue within each marketing channel. ROW_NUMBER assigns a sequential number to each row within its partition.

This lets you rank campaigns within each channel (paid_search, paid_social, email, etc.) and then filter to only keep the top 3. Without window functions, this would require complex subqueries or multiple queries.

Use Case: Rank Keywords by Conversion Rate

RANK is similar to ROW_NUMBER but handles ties. If two keywords have the same conversion rate, they get the same rank, and the next rank is skipped.

This is useful when you want to identify your most efficient keywords while acknowledging that multiple keywords might perform equally well.

LAG and LEAD: Time-Based Comparisons

Use Case: Day-Over-Day Revenue Change

LAG looks at the previous row. Use it to compare today's metrics with yesterday's:

Calculate each day's revenue, the previous day's revenue using LAG(revenue, 1), and then compute the percentage change. This gives you an instant daily performance tracker without needing to self-join the table.

Use Case: Week-Over-Week Campaign Performance

Use LAG with an offset of 7 to compare each day with the same day last week:

LAG(impressions, 7) OVER (PARTITION BY campaign_id ORDER BY date) gives you the same day from last week. This accounts for day-of-week patterns that simple day-over-day comparisons miss.

Use Case: Next Touchpoint Analysis

LEAD looks at the next row. Use it for customer journey analysis:

For each customer touchpoint, LEAD(channel, 1) shows what channel they interacted with next. This reveals common channel sequences and informs your multi-channel strategy.

Running Totals: Cumulative Metrics

Use Case: Cumulative Ad Spend by Month

A running total with SUM() OVER() shows cumulative spend over time:

SUM(spend) OVER (PARTITION BY channel ORDER BY date) gives you the running total of spend for each channel. This is essential for budget pacing—seeing whether you're on track to hit monthly or quarterly spend targets.

Use Case: Cumulative Conversions for Pacing

Same pattern applied to conversions shows whether you're on track to hit your monthly conversion target. Partition by month and channel to see cumulative progress independently for each segment.

Moving Averages: Smoothing Noisy Data

Use Case: 7-Day Moving Average of Revenue

Marketing data is noisy—weekday/weekend patterns, random fluctuations, and one-off events make daily data hard to read. A moving average smooths it out.

AVG(revenue) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) gives you the 7-day moving average. This is invaluable for dashboards and trend analysis.

Use Case: 30-Day Moving Average of CAC

Customer acquisition cost fluctuates daily. A 30-day moving average reveals the true trend:

This helps you see whether CAC is genuinely increasing or if today's spike is just noise.

FIRST_VALUE and LAST_VALUE: Attribution

Use Case: First-Touch Attribution

FIRST_VALUE(channel) OVER (PARTITION BY user_id ORDER BY timestamp) returns the first channel each user interacted with. This powers first-touch attribution reporting.

Use Case: Last-Touch Before Conversion

Find the last marketing channel a user interacted with before converting. Combine LAST_VALUE with a window frame limited to rows before the conversion event.

NTILE: Percentile Analysis

Use Case: Customer Segmentation by Spend

NTILE(4) OVER (ORDER BY total_spend DESC) divides customers into four equal quartiles by spending. This creates instant customer segments:

  • Q1: Top 25% spenders (VIP/whale customers)
  • Q2: Above average spenders
  • Q3: Below average spenders
  • Q4: Bottom 25% (dormant or low-value)

Use Case: Campaign Performance Percentiles

NTILE(10) creates deciles. Use this to find which campaigns are in the top 10% for ROAS or bottom 10% for CPA. These extreme performers deserve the most attention.

Combining Window Functions

The real power comes from combining multiple window functions:

Use Case: Campaign Performance Scorecard

In a single query, you can calculate:

  • RANK() for campaign rank by revenue within each channel
  • LAG() for week-over-week revenue change
  • SUM() OVER() for cumulative monthly spend
  • AVG() OVER() for 7-day moving average of conversion rate
  • NTILE() for performance percentile ranking

This gives you a comprehensive campaign scorecard in one query that would otherwise require multiple queries and manual assembly.

Performance Tips

  • Window functions can be computationally expensive on large datasets. Add WHERE clauses to limit the date range before applying window functions.
  • PARTITION BY creates separate windows. Choose partitions carefully—too many small partitions reduce the usefulness of aggregations.
  • Use CTEs (WITH clauses) to make complex window function queries readable. Build up in layers.
  • Not all window functions require ORDER BY. Simple aggregations like SUM() OVER (PARTITION BY channel) don't need ordering.
  • Test with small datasets first. Window functions are harder to debug than simple aggregations.

Practice Exercises

  1. Calculate the 7-day moving average of daily signups for each marketing channel
  2. Rank your top 5 landing pages by conversion rate for each month
  3. Calculate the day-over-day percentage change in ad spend for each campaign
  4. Find each user's first and last marketing touchpoint before their first purchase
  5. Create a cumulative revenue chart that shows running total by channel over the quarter

Bottom Line

SQL window functions transform what you can do with marketing data. They eliminate the need for complex self-joins, multiple queries, and spreadsheet gymnastics. Once you master ROW_NUMBER, LAG, running totals, and moving averages, you'll find yourself using them in nearly every analysis. The investment in learning window functions pays off immediately in faster, more elegant, and more insightful marketing analysis.

Ready to Find Your Next Marketing Analytics Role?

Jobsolv uses AI to match you with the best marketing analytics jobs and tailor your resume for each application.

Get weekly job alerts

Curated marketing analytics roles — delivered every Monday.

Atticus Li

Hiring manager for marketing analysts and career coach. Champions underdogs and high-ambition individuals building careers in marketing analytics and experimentation.

Related Articles