Interview question
Calculate a running account balance
Uses an ordered window aggregate to calculate a deterministic running balance per account.
TL;DR
Uses an ordered window aggregate to calculate a deterministic running balance per account.
Window aggregates, partitioning, deterministic row order, signed amounts, and ledger semantics.
Practice the problem like a real interview: restate, reason, implement, and test.
Table: LedgerEntries(EntryId, AccountId, PostedAtUtc, EntryType, Amount), where EntryType is Credit or Debit and Amount is positive. Return a signed amount and running balance for each account.
A credit of 100 followed by a debit of 30 produces running balances 100 and 70. Accounts are calculated independently.
AccountId.EntryId.ROWS frame.I first translate each row into a signed amount. The running balance is a cumulative SUM partitioned by account. Adding EntryId to the timestamp order makes simultaneous entries deterministic, and ROWS UNBOUNDED PRECEDING makes the frame operate on physical ordered rows rather than peer groups.
WITH SignedEntries AS
(
SELECT
e.EntryId,
e.AccountId,
e.PostedAtUtc,
CASE
WHEN e.EntryType = 'Credit' THEN e.Amount
WHEN e.EntryType = 'Debit' THEN -e.Amount
END AS SignedAmount
FROM dbo.LedgerEntries AS e
)
SELECT
EntryId,
AccountId,
PostedAtUtc,
SignedAmount,
SUM(SignedAmount) OVER
(
PARTITION BY AccountId
ORDER BY PostedAtUtc, EntryId
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS RunningBalance
FROM SignedEntries
ORDER BY AccountId, PostedAtUtc, EntryId;
The window requires rows ordered per account. An index on (AccountId, PostedAtUtc, EntryId) including type and amount can reduce sorting. Large ledger exports may still process substantial history, so bounded ranges or stored opening balances can be useful.
Move to the linked follow-up, next path step, prerequisite, or deeper variant.
Practice the next layer of the same subject.