Skip to the solution
MediumDSA14 min read

How do you calculate a running total or moving average?

721 views

The problem

Question presented to candidate: "Given a table of daily sales per store, how would you add a running total, and a 3-day moving average, to every row? What exactly decides which rows go into each calculation?"

What a strong answer should cover:

  • A running total is SUM(amount) OVER (PARTITION BY store ORDER BY day ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW); a moving average is AVG(...) with a bounded frame such as ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
  • The frame clause decides the rows: ROWS counts physical rows, RANGE uses value distance on the ORDER BY column (peers included), GROUPS counts distinct peer groups
  • The default frame with ORDER BY is RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, so rows tied on the order key share one running value; use ROWS plus a unique tiebreaker for a strict row-by-row total
  • Missing dates: "last 3 rows" is not "last 3 days"; use RANGE BETWEEN INTERVAL '2 days' PRECEDING AND CURRENT ROW (PostgreSQL 11+) or a numeric day key, or fill the gaps first
  • The first rows of a moving average have short frames (fewer than 3 rows); count the frame and blank them if only full windows are wanted

Clarifying questions expected:

  • Should the total restart per store (or per month), or run across everything?
  • Are there missing days, and should "3-day" mean three calendar days or three rows?
  • Can several rows share the same date, and if so, should they be summed together?

Code / implementation expected: Yes β€” a running total with PARTITION BY and a moving average with an explicit ROWS frame.

Schema used by the examples:

  • window-functions
  • analytics

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

14 min read Β· 12 sections

Run the code

Edit the query and run it against the tables for this question.

SQLRunning total per store, next to the store total
SQL3-row moving average for store A, with the number of rows in each frame
SQLThe default frame (RANGE) vs ROWS when two orders share a day
PostgreSQL: last 3 rows vs last 3 calendar days when a day is missing
SELECT day::date AS day, amount,
       SUM(amount) OVER (ORDER BY day::date
                         ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS last_3_rows,
       SUM(amount) OVER (ORDER BY day::date
                         RANGE BETWEEN INTERVAL '2 days' PRECEDING AND CURRENT ROW) AS last_3_days
FROM daily_sales
WHERE store = 'A'
ORDER BY day;

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 41 of 82 in SQL

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All SQL questions
Up nextMedium

How do you update a table based on another table?

Continue