Cart Sizes

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

An analyst noticed the bulk-checkout invite list was counting refunds and zero-value adjustments in transactions as purchases, which pushed the wrong buyers over the bar. Rebuild it from purchases with a positive amount only: every user in users with more than twelve of them, showing their username, purchase count and total spent, biggest spenders first.

Power buyers. Big carts.

Tables

users

Columns: user_id INTEGER, username TEXT, email TEXT, signup_date TEXT, account_status TEXT, age_bucket TEXT

users: 10 of 200 rows
user_idusernameemailsignup_dateaccount_statusage_bucket
100alicealice@example.com2025-02-02inactive25-34
197aaron42aaron42@example.com2026-03-03suspended35-44
294 ameliaamelia@example.com2024-04-04pending_verification45-54
391arjun arjun@example.com2025-05-05active55-64
488ava99ava99@example.com2026-06-06inactive65+
585andrew_kandrew_k@example.com2024-07-07suspendedNULL
682anikaanika@example.com2025-08-08 16:34:00pending_verification18-24
779aidenaiden@example.com2026-09-09 14:53:00active25-34
876aria_baria_b@example.com2024-10-10inactive35-44
973brianbrian@example.com2025-11-11suspended45-54

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 10 rows
usernamepurchase_counttotal_spent
bjorn991410511.76
brian1310191.96
aria_b1410134.6
aiden149946.02
andrew_k139491.52

Worked solution and explanation

What this really is

Under the invite-list story this is two filters living at two different grains. The positive-amount rule decides which ledger rows are purchases at all; the more-than-twelve bar decides which users survive once those purchases are counted. Anyone can write the join and the count. What separates candidates is putting each filter where its data lives. Every buyer on this data sits at twelve or fourteen ledger rows, so the bar is right on the edge: let a refund row into the count and a buyer can clear it on a purchase they gave back.


Build it in order

Step 1: Attribute each purchase to a buyer

Inner-join users to transactions on user_id. Users with no purchases can never reach thirteen, so the inner join loses nothing the answer needs.

Step 2: Throw out non-purchases before counting

WHERE t.total_amount > 0 is a row condition: it looks at one ledger row at a time, so it runs before grouping and keeps the zero-value row and the refund out of both COUNT(*) and SUM(t.total_amount).

Step 3: Count and total per user_id

GROUP BY u.user_id, u.username keys the group on the primary key and carries the display name along, so two people who share a username never merge.

Step 4: Cut on the count, then sort by spend

HAVING COUNT(*) > 12 filters groups after they are counted, and ORDER BY total_spent DESC puts the biggest spenders on top. The count decides who is on the list; the spend decides where they sit.

Filter the rows, cut the groups
SELECT u.username,
       COUNT(*) AS purchase_count,
       SUM(t.total_amount) AS total_spent
FROM users AS u
JOIN transactions AS t
  ON t.user_id = u.user_id
WHERE t.total_amount > 0
GROUP BY u.user_id, u.username
HAVING COUNT(*) > 12
ORDER BY total_spent DESC
Row filter
WHERE sees one ledger row at a time. It can test total_amount, but no per-user count exists yet, so WHERE COUNT(*) > 12 is rejected outright.
Group filter
HAVING sees one user at a time, after counting. It can test COUNT(*), but by then the individual total_amount values are gone, so the refund rule cannot live here.

Common follow-up questions