Closing the Books
An easy SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.
- Domain
- SQL
- Difficulty
- easy
- Seniority
- L3
Problem
Produce a single revenue figure for April 2026 from transactions, the number finance needs to close that month. Despite its name, total_amount is recorded per unit, so a sale brings in its quantity times that amount.
April is done. Finance wants the number, and it isn't the one printed on the invoice line.
Tables
transactions
Columns: transaction_id INTEGER, user_id INTEGER, product_id INTEGER, quantity INTEGER, total_amount REAL, transaction_date TEXT
| transaction_id | user_id | product_id | quantity | total_amount | transaction_date |
|---|---|---|---|---|---|
| 1067 | 197 | 1001 | 2 | 23.46 | 2026-02-02 |
| 1134 | 294 | 1050 | 3 | 36.93 | 2026-03-03 |
| 1201 | 391 | 1099 | 4 | 50.4 | 2026-04-04 |
| 1268 | 488 | 1148 | 5 | 63.87 | 2026-05-05 |
| 1335 | 585 | 1197 | 0 | 0 | 2026-06-06 |
| 1402 | 682 | 1246 | 2 | 90.81 | 2026-07-07 |
| 1469 | 779 | 1295 | 3 | 104.28 | 2026-08-08 |
| 1536 | 876 | 1344 | 4 | 117.75 | 2026-09-09 |
| 1603 | 973 | 1393 | 5 | -45 | 2026-01-10 |
| 1670 | 1070 | 1442 | 1 | 144.69 | 2026-02-11 |
customers
Columns: customer_id INTEGER, first_name TEXT, last_name TEXT, country TEXT
| customer_id | first_name | last_name | country |
|---|---|---|---|
| 40089 | Priya | Gupta | India |
| 40178 | Luca | Rossi | Italy |
| 40267 | Ava | Nguyen | Vietnam |
| 40356 | Ethan | Johnson | Spain |
| 40445 | Maria | Garcia | China |
| 40534 | Chen | Wei | Russia |
| 40623 | Sofia | Petrova | Ireland |
| 40712 | Liam | O'Connor | Mexico |
| 40801 | Isabella | Martinez | Canada |
| 40890 | Noah | Brown | France |
Expected output
| total_revenue |
|---|
| 24632.58 |
Worked solution and explanation
What this really is
This is a sum of per-row products wearing a month-close costume, with a decoy table on the side. Nothing about one month's revenue depends on who the customer is, so customers is bait: leave it alone. Everyone gets the April filter. What separates candidates is where the multiplication happens. total_amount is a per-unit amount, so revenue only exists after each row's quantity scales it, and that product has to be formed row by row before anything is totaled. Skip the scaling and you undercount every multi-unit sale; multiply two totals instead and you inflate the month many times over.
Step 1: Fence the month before you total anything
strftime('%Y-%m', t.transaction_date) = '2026-04' turns each date into a 'YYYY-MM' string and keeps only the April rows. One equality on the formatted month is harder to get wrong than a pair of boundaries, and it keeps working if the column ever gains a time of day.
Step 2: Total the per-row product
With the month fenced, SUM(t.quantity * t.total_amount) collapses the surviving rows into the one figure finance asked for. Alias it total_revenue so the single output column says exactly what it is.
SELECT SUM(t.quantity * t.total_amount) AS total_revenue
FROM transactions t
WHERE strftime('%Y-%m', t.transaction_date) = '2026-04'One table, one filter, one aggregate of a product. No join earns its keep here.
- Product of totals
SUM(quantity) * SUM(total_amount)pairs every row's units with every other row's amount. Two April sales, 4 units at 50.40 and 1 unit at 144.69, become 5 times 195.09, about 975.- Total of products
SUM(quantity * total_amount)multiplies inside each row first: 201.60 plus 144.69 is 346.29, the money those two sales actually brought in.
Common follow-up questions
- Now break it out by month instead of just April, one revenue row per calendar month, most recent first. (Tests moving from a single filter to a grouped aggregate over the formatted month.)
- Finance now wants April revenue split by customer country. How does `customers` come back into play? (Tests recognizing when a join is actually load-bearing, joining on the right key, and noticing that some `customer_id` values repeat.)