Crowned Together

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
General Assembly

Problem

Our VIP award goes to whoever has the most transactions on record in transactions, and when several users share that top count we honor every one of them. Pull the winners' usernames from users.

Some thrones seat more than one.

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
username
aaron42
amelia
arjun
ava99
andrew_k

Worked solution and explanation

The crown is shared

This is a top-N-with-ties problem wearing the costume of a single winner. The phrase 'the user with the most transactions' begs for ORDER BY COUNT(*) DESC LIMIT 1, and that is the trap: on this data five users sit tied at the top, and LIMIT 1 keeps one of them, chosen by whatever order the engine happened to produce. Everyone gets the count right. What separates candidates is whether they compare every user against the maximum instead of taking the first row. Miss it and four people who earned the award never hear about it.

Build it in three moves

Step 1: Count each user's transactions as per_user

Group transactions by user_id and take COUNT(*) as txn_count, wrapped as the derived table per_user. Each row is one transaction, so quantity and total_amount are irrelevant here; summing either one answers a different question.

Step 2: Find the ceiling with MAX(txn_count)

The scalar subquery cannot see per_user, so it restates the same aggregate as all_counts and takes MAX(txn_count) over it. The result is one number: the ceiling every candidate winner is measured against.

Step 3: Keep everyone who reaches it

Filter per_user.txn_count against that ceiling in the WHERE. Every user at the number survives, however many there are, and the join to users exists only to swap user_id for username.

All users tied at the top count
SELECT u.username
FROM (
    SELECT user_id, COUNT(*) AS txn_count
    FROM transactions
    GROUP BY user_id
) per_user
JOIN users u ON u.user_id = per_user.user_id
WHERE per_user.txn_count = (
    SELECT MAX(txn_count)
    FROM (
        SELECT user_id, COUNT(*) AS txn_count
        FROM transactions
        GROUP BY user_id
    ) all_counts
)
Picks one winner
ORDER BY COUNT(*) DESC LIMIT 1 returns a single row. With five users tied, which one survives depends on engine order, so it is both wrong and unstable between runs.
Honors every winner
WHERE per_user.txn_count = (SELECT MAX(txn_count) ...) compares each user to the ceiling. One winner or fifty, the result is exactly the set that earned it.

Common follow-up questions