The Spending Floor
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
- Asked in
- Shopify
Problem
The pricing team is looking at each user's lowest-value purchase to understand the floor of what people are willing to spend. Show the user ID, username, and their smallest transaction amount, from the lowest up.
Everyone has a smallest purchase.
Tables
users
Columns: user_id INTEGER, username TEXT, email TEXT, signup_date TEXT, account_status TEXT, age_bucket TEXT
| user_id | username | signup_date | account_status | age_bucket | |
|---|---|---|---|---|---|
| 100 | alice | alice@example.com | 2025-02-02 | inactive | 25-34 |
| 197 | aaron42 | aaron42@example.com | 2026-03-03 | suspended | 35-44 |
| 294 | amelia | amelia@example.com | 2024-04-04 | pending_verification | 45-54 |
| 391 | arjun | arjun@example.com | 2025-05-05 | active | 55-64 |
| 488 | ava99 | ava99@example.com | 2026-06-06 | inactive | 65+ |
| 585 | andrew_k | andrew_k@example.com | 2024-07-07 | suspended | NULL |
| 682 | anika | anika@example.com | 2025-08-08 16:34:00 | pending_verification | 18-24 |
| 779 | aiden | aiden@example.com | 2026-09-09 14:53:00 | active | 25-34 |
| 876 | aria_b | aria_b@example.com | 2024-10-10 | inactive | 35-44 |
| 973 | brian | brian@example.com | 2025-11-11 | suspended | 45-54 |
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 |
Expected output
| user_id | username | min_amount |
|---|---|---|
| 973 | brian | -45 |
| 585 | andrew_k | 0 |
| 197 | aaron42 | 23.46 |
| 294 | amelia | 36.93 |
| 391 | arjun | 50.4 |
Worked solution and explanation
What this really is
Beneath the pricing-floor story this is aggregation-per-entity: one row per user carrying that user's minimum spend, then sorted by that minimum. Anyone can type MIN and GROUP BY. Two things separate the candidates. First, MIN, not COUNT or SUM: the ask is the single cheapest purchase, so reflexing to a total or a tally answers a different question entirely. Second, the join is an inner join, so a user who never bought anything simply is not there; reach for an outer join and you invent null-priced floors for people who have no floor at all.
Walking it
Step 1: Attach the username
Join on user_id so each transaction carries its owner's username. An inner join is the whole point here: it silently drops users who never transacted, which is exactly the behavior the floor metric wants.
Step 2: Collapse to the minimum
GROUP BY u.user_id, u.username with MIN(t.total_amount) collapses each user's many purchases down to their single cheapest one. Every non-aggregated column in the SELECT has to appear in the GROUP BY, which is why username rides alongside user_id.
Step 3: Sort cheapest first
ORDER BY min_amount ASC puts the lowest floors on top, so the cheapest spenders lead the list.
The solution
SELECT u.user_id, u.username, MIN(t.total_amount) AS min_amount
FROM users u
JOIN transactions t ON u.user_id = t.user_id
GROUP BY u.user_id, u.username
ORDER BY min_amount ASCCommon follow-up questions
- How would you also show the product of the cheapest transaction? (Tests first-per-group pattern: a window function or correlated subquery to retrieve the full row, since MIN alone gives only the value.)
- What if several transactions share a user's minimum amount? (MIN returns one value; surfacing all tied rows requires ranking or a self-join back to the minimum.)
- How would you include users with zero transactions? (Tests LEFT JOIN and NULL handling for users with no matching transactions.)