The Podium Finish

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
Meta

Problem

For each category, return the top 2 products by total quantity sold. If products tie in quantity within a category, break the tie alphabetically by product name and assign consecutive ranks. Only include rows ranked 1 or 2.

Top two products per category.

Tables

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

products

Columns: product_id INTEGER, product_name TEXT, category TEXT, price REAL, rating REAL, in_stock INTEGER

products: 10 of 200 rows
product_idproduct_namecategorypriceratingin_stock
1001Basic Device 1XBooks17.522.71
1050Deluxe Bundle 2XClothing25.054.41
1099Pro Unit 3XHome & Kitchen32.582.11
1148Ultra Tool 4XCollectibles40.113.81
1197Essential Set 5XToys47.641.51
1246Classic System 6XBeauty03.21
1295Smart Gadget 7XAutomotive62.74.90
1344Eco Kit 8XGarden70.232.61
1393Turbo Pack 9XMusic77.764.30
1442Premium Widget 10XElectronics85.2921

Expected output

First 5 of 22 rows
categoryproduct_nametotal_quantityrank
AutomotiveSmart Gadget 27X61
AutomotiveSmart Gadget 37X62
BeautyClassic System 26X41
BeautyClassic System 36X42
BooksBasic Device 1X61

Worked solution and explanation

Why this problem exists in real interviews

Top-N per group is one of the most common SQL patterns in product analytics: top customers per cohort, top SKUs per category, top contributors per repo. Interviewers reach for it because it forces you to combine a join, a GROUP BY aggregate, a windowed ranking with PARTITION BY, and a final filter, all in a single coherent query. Doing it cleanly tells them you understand which step belongs in which clause.


Break down the requirements

Step 1: Sum quantity per (category, product_name)

Inner-join transactions t to products p on product_id, then GROUP BY p.category, p.product_name and compute SUM(t.quantity) AS total_quantity. This collapses 100M transactions down to one row per product within its category.

Step 2: Rank products inside each category

Wrap the aggregate in a CTE and apply ROW_NUMBER() OVER (PARTITION BY category ORDER BY total_quantity DESC, product_name ASC). PARTITION BY category resets the rank for every category, the DESC clause puts the heaviest sellers first, and the secondary product_name ASC is the prompt's deterministic tiebreak so two products with identical quantities get rank 1 and 2 in alphabetical order.

Step 3: Keep ranks 1 and 2, then sort the output

Filter WHERE rank <= 2 to take the top two per category, then ORDER BY category, rank to produce the four required output columns: category, product_name, total_quantity, rank.


The solution

Aggregate, rank within category, take top two
WITH product_qty AS (
  SELECT p.category, p.product_name, SUM(t.quantity) AS total_quantity
  FROM transactions t INNER JOIN products p ON t.product_id = p.product_id
  GROUP BY p.category, p.product_name
),
ranked AS (
  SELECT category, product_name, total_quantity,
         ROW_NUMBER() OVER (PARTITION BY category ORDER BY total_quantity DESC, product_name ASC) AS rank
  FROM product_qty
)
SELECT category, product_name, total_quantity, rank FROM ranked WHERE rank <= 2

Common follow-up questions