N040 Tier 3 · Intermediate

Aggregate Window Functions (SUM, AVG, COUNT OVER) in SQL

The aggregate functions `SUM`, `AVG`, `COUNT`, `MIN`, and `MAX` can be used as window functions by attaching an `OVER` clause. Without `ORDER BY` inside `OVER`, they compute a static value across the entire partition. With `ORDER BY` inside `OVER`, they compute a running value that accumulates as it moves through the partition.

SUM, AVG, and COUNT used with OVER give you two different behaviors depending on whether you include ORDER BY inside OVER.

Without ORDER BY inside OVER, the aggregate computes a single value for the partition and places that same value on every row. With ORDER BY inside OVER, the aggregate accumulates: each row gets the sum (or average, or count) of all rows up to and including its position in the ordering. These are two different analytical questions, and the presence or absence of ORDER BY is what separates them.

You're tracking order revenue over time. You want each order to show both the overall total and the running total as of that date:

grand_total is the same on every row — the sum of all orders. running_total starts small and grows with each row. On the last row, it equals grand_total.

The same logic applies to other aggregates. Add PARTITION BY to reset within groups:

SUM(total_amount)   OVER (PARTITION BY status ORDER BY created_at)  -- running total per status
AVG(total_amount)   OVER (PARTITION BY status ORDER BY created_at)  -- running average per status
COUNT(*)            OVER (PARTITION BY status ORDER BY created_at)  -- running count per status

Each accumulates within its partition, restarting at the start of each new group.

COUNT(*) counts rows regardless of NULL. COUNT(column) counts only non-NULL values. SUM, AVG, MIN, and MAX all skip NULL values, consistent with how they behave as regular aggregates.

The one thing that trips people up: when multiple rows share the same ORDER BY value, the running total jumps ahead.

PostgreSQL's default behavior for ordered windows groups rows with the same sort value together and includes all of them in each other's running total. If three orders all have the same created_at timestamp, each of those three rows shows a running total that already includes all three of their amounts — not a strict row-by-row accumulation.

This is called RANGE mode. If you want strict row-by-row accumulation regardless of equal sort values, add ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:

SUM(total_amount) OVER (
  ORDER BY created_at
  ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)

In ROWS mode, each row accumulates only up to its own physical position. For time-series work where multiple events share a timestamp, this usually produces the result you expect.

Check your understanding

You write SUM(revenue) OVER (ORDER BY order_date). Two rows share the same order_date. What does each row's running total include?

Practice

9 Aggregate Window Functions (SUM, AVG, COUNT OVER) practice problems

Write a query to return the ID and amount of every order, plus the running total of `total_amount` accumulated from the first order through that order in order of `id`.

easy ecommerce

Write a query to return the ID and status of every order, plus the running count of orders from the first record through that order in order of `id`.

easy ecommerce

Write a query to return the ID, name, and price of every product, plus the running average price accumulated from the first product through that product in order of `id`.

easy ecommerce

Write a query to return the ID, status, and amount of every order, plus the running total of `total_amount` within the order's status, ordered by `id`.

medium ecommerce

Write a query to return the ID, customer ID, and total amount of every order, plus the running count of orders placed by that customer, accumulated in order of `id`.

medium ecommerce

Write a query to return the ID and amount of every order, plus the grand total of `total_amount` across every order and the running total accumulated through that order in order of `id`.

medium ecommerce

Write a query to return the ID, name, and price of every product, plus the running minimum and running maximum `price` observed from the first product through that product in order of `id`.

medium ecommerce

Write a query to return the ID, name, and price of every product, plus the running sum of `price` ordered by `price` ascending. Sort the final result by `price` ascending.

hard ecommerce

Write a query to return the ID and amount of every order, plus a running total of `total_amount` that adds exactly one order's amount per row, ordered by `id`.

hard ecommerce

These problems are part of the Aggregate Window Functions (SUM, AVG, COUNT OVER) lesson in SQLMaxx, with instant grading and a worked solution on each.

How you actually get good at SQL

Reading explains SQL. Writing it, over and over with instant feedback, is what makes you fluent.

That's the whole SQLMaxx loop: 600+ real problems, instant AI feedback, mastery you can actually see, and spaced review that won't let you forget.

A stack of SQL practice problem cards, the top card showing an employees table.
615 problems · 66 concepts

Real problems. Not toy examples.

615 hand-built problems spanning all 66 concepts, from basic SELECTs to window functions, built on real schemas and real business questions, the kind you'll actually get asked on the job. Enough reps to make SQL automatic.

A retro computer showing a SQL query marked correct with a green checkmark.
Instant AI feedback

Write a query. Know if it's right in one second.

No copying an answer and hoping it clicked. The AI grader checks your real query against real data, catches exactly what's wrong, and explains the fix in plain English, like a senior analyst reading over your shoulder on every problem.

A circular mastery progress dial filling from blue to green, the SQLMaxx diamond at its center.
Mastery tracking

Stop guessing whether you actually know it.

SQLMaxx tracks every concept and shows you what you've mastered and what's still shaky. Your skills fill in one concept at a time, so 'I think I get joins' becomes something you can prove.

A SQL query editor circled by a blue return arrow with a clock, scheduled to come back for review.
Spaced review

Learn it once. Keep it for good.

Most of what you learn this week fades by next week. So when a concept comes due for review, SQLMaxx hands you a fresh problem to solve from a blank editor, not a flashcard to re-read. A research-backed spaced-repetition algorithm (FSRS) times each return for right before you'd forget, so your SQL is still there months later, when the interview or the job actually needs it.

Practice, feedback, mastery, review. That's the loop that turns reading into real skill.

Start free

No account, no credit card. Start solving in under a minute.