The Long Climb

A medium SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.

Domain
SQL
Difficulty
medium
Seniority
L4
Asked in
Goldman Sachs

Problem

Every customer shows up as one lifetime spend figure in the finance team's review, and nobody can see how that figure built up purchase by purchase. From the transactions table, list every purchase beside that customer's cumulative spend up to and including it, customers by ascending user_id and each customer's purchases oldest first, with same-day purchases taken in transaction_id order.

Each purchase stacks on the last. Watch it climb.

Tables

transactions

Columns: transaction_id INTEGER, user_id INTEGER, product_id INTEGER, quantity INTEGER, total_amount REAL, transaction_date TEXT

transactions: 10 of 200 rows
transaction_iduser_idproduct_idquantitytotal_amounttransaction_date
10671971001223.462026-02-02
11342941050336.932026-03-03
12013911099450.42026-04-04
12684881148563.872026-05-05
13355851197002026-06-06
14026821246290.812026-07-07
146977912953104.282026-08-08
153687613444117.752026-09-09
160397313935-452026-01-10
1670107014421144.692026-02-11

Expected output

First 5 of 200 rows
user_idproduct_idtotal_amounttransaction_datecumulative_sales
10053621222.292026-01-071222.29
1003157616.142026-01-181838.4299999999998
1002422414.092026-03-032252.52
10046271020.242026-03-203272.7599999999998
1002422414.092026-04-033686.85

Worked solution and explanation

What this problem really is

Strip off the finance framing and this is a per-customer prefix sum that has to keep every original row. That last part is the whole game: reach for a GROUP BY and each customer collapses to one line, losing the purchase-by-purchase climb the report needs. So it has to be a windowed SUM that walks each customer's timeline while every row survives. The trap is in the ordering. If you order the window by transaction_date alone, two purchases on the same day become peers. The default frame then gives both of them the total through the end of that day, so two steps in the climb flatten into one. Settle the tie with transaction_id and every row gets its own step.


Break down the requirements

Step 1: Keep every transaction

Read each row from transactions (user_id, product_id, total_amount, transaction_date). Do not aggregate: the output keeps one row per input row.

Step 2: Accumulate per customer

Compute the accumulating total of total_amount with SUM() over a window scoped by PARTITION BY user_id. Each customer's climb is then independent and never picks up another user's spend.

Step 3: Order the window deterministically

Order the window by transaction_date, transaction_id. The date makes the sum run up to and including the current row. transaction_id is the tiebreak that gives same-day rows separate steps instead of a shared value.

Step 4: Pin the output order

Sort the output the same way: ORDER BY user_id, transaction_date, transaction_id. transaction_id is not in the output, but it still decides the sequence of same-day rows, so the result order is fully fixed.


The solution

Partitioned running total
SELECT
    user_id,
    product_id,
    total_amount,
    transaction_date,
    SUM(total_amount) OVER (
        PARTITION BY user_id
        ORDER BY transaction_date, transaction_id
    ) AS cumulative_sales
FROM transactions
ORDER BY user_id, transaction_date, transaction_id

Common follow-up questions