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 isAVG(...)with a bounded frame such asROWS BETWEEN 2 PRECEDING AND CURRENT ROW - The frame clause decides the rows:
ROWScounts physical rows,RANGEuses value distance on theORDER BYcolumn (peers included),GROUPScounts distinct peer groups - The default frame with
ORDER BYisRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, so rows tied on the order key share one running value; useROWSplus 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: