N040-H2 Tier 3 · Intermediate · hard ecommerce · Brightlane

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`

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

The problem

Brightlane's finance team needs a strict row-by-row running total of order amounts that accumulates one order at a time even when multiple orders share the same total_amount.

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.

Assumptions:

  • The orders table has one row per order with an id and a total_amount.
  • Orders are processed in ascending id order. The running total at each row is the combined total_amount of every order at that row's id or earlier, counted strictly by physical row position rather than by ties on the ordering value.
  • Two orders with the same total_amount do not share a running total — each row contributes its own amount independently to the row-by-row sequence.

Output:

  • One row per order, with columns id, total_amount, and running_total.
Schema · ecommerce 5 tables
categories
id integer
name text
parent_id? integer
products
id integer
name text
category_id integer
price numeric
stock_qty integer
attributes? jsonb
order_items
id integer
order_id integer
product_id integer
quantity integer
unit_price numeric
customers
id integer
name text
email text
city? text
country text
created_at timestamptz
is_active boolean
orders
id integer
customer_id integer
ordered_at timestamptz
status text
total_amount numeric

Run previews · Check grades

Write a query, then run it to see results here.

Worked solution Try it yourself first
Solution query
SELECT
  id,
  total_amount,
  SUM(total_amount) OVER (
    ORDER BY
      id ROWS BETWEEN UNBOUNDED PRECEDING
      AND CURRENT ROW
  ) AS running_total
FROM
  orders

The shape

ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW overrides PostgreSQL's default ordered-window frame and forces a strict row-by-row accumulation. Where the default RANGE frame would group tied values into a single peer group and assign every tied row the same running total, the explicit ROWS frame counts physical rows. Each row contributes its own total_amount exactly once, and the running total advances by one row at a time even when two orders share the same amount.

Clause by clause

  • SELECT id, total_amount returns each order's identifier and amount. The strict running total is attached.
  • SUM(total_amount) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total is the window expression. ORDER BY id sequences the rows. The ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW clause sets the frame explicitly: include every row from the first one through the current row's physical position, and stop there. The first order's running_total is its own amount. The second order's running total adds the first order's amount once. Each subsequent row adds one more order's amount to the accumulator.
  • FROM orders reads every order. Every row contributes once to its own running total and to the running totals of all rows that come after it.

Why the explicit ROWS frame instead of the default

The default frame for ORDER BY id inside OVER is RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. Under RANGE mode, "current row" means every row sharing the current row's ordering value. If two orders had the same id, they would form a peer group and receive the same running total. ROWS mode replaces value equality with physical position: "current row" means this row and no other. The frame boundaries become row positions, not value boundaries, and ties on the ordering expression no longer affect the result.

The trap

On a table where the ordering column is unique, the default frame and the ROWS frame produce the same numbers, which can leave the distinction looking decorative. It is not. The moment ties appear on the ordering expression — same id, same order_date, same total_amount if you ever sort by it — the default frame silently groups them, and the running totals jump in steps larger than one row. The query still runs and the numbers still look plausible. When a strict row-by-row accumulation is what the report needs, write the frame explicitly. The few extra keystrokes are what keep the behavior pinned to physical position rather than to value equality.

You practiced the explicit ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW frame — switch from default RANGE mode to ROWS mode to enforce strict row-by-row accumulation, ignoring peer-group ties on the ordering value.

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.