The Standings

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
L5

Problem

In these standings, categories that moved the same number of units share a standing, and the next category's standing still counts every category above it. A merchandising analyst needs every category's total revenue and total units from transactions, each sale's category coming from products, along with its standing by units with the biggest mover in first place.

Every category earns its place on the board. Find where each one lands.

Tables

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

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 11 rows
categorytotal_revenuetotal_unitsposition
Music11884.14901
Home & Kitchen12222722
Garden12087.3722
Sports11670.18704
Clothing12487.92575

Worked solution and explanation

What this problem is really about

Under the merchandising framing this comes down to one question: when two categories move the same number of units, what standing does the next one get? Anyone can join, sum and sort. The skill is numbering standings so that a tie shares a place and the place after it still counts every category above. On this data that matters twice: 'Home & Kitchen' and 'Garden' both move 72 units, and 'Electronics' and 'Collectibles' both move 20. ROW_NUMBER() splits each pair. DENSE_RANK() keeps each pair together but closes the gap, so 'Sports' reads 3 instead of 4 and 'Toys' reads 9 instead of 11. In both cases the standings look plausible and are wrong from the third row down.


Build it in three moves

Step 1: Join transactions to products

Join on product_id to give each sale its category. Make it an inner join: 18 sales carry no product_id, and an outer join from transactions would turn them into a twelfth row with a NULL category.

Step 2: Total each category

SUM(t.total_amount) is the revenue and SUM(t.quantity) is the units, grouped by p.category. The refund and the voided sale stay in, because they are recorded sales and the totals are what was recorded.

Step 3: Place categories by units

RANK() OVER (ORDER BY SUM(t.quantity) DESC) reads the grouped total directly, because window functions run after GROUP BY. The descending direction puts the biggest mover in place 1.


The solution

Standings by units moved
SELECT
    p.category,
    SUM(t.total_amount) AS total_revenue,
    SUM(t.quantity) AS total_units,
    RANK() OVER (ORDER BY SUM(t.quantity) DESC) AS position
FROM products p
JOIN transactions t ON p.product_id = t.product_id
GROUP BY p.category
Gapless numbering
DENSE_RANK() by units: 'Music' 1, 'Home & Kitchen' 2, 'Garden' 2, 'Sports' 3, then down to 'Electronics' 8, 'Collectibles' 8, 'Toys' 9.
Standings
RANK() by units: 'Music' 1, 'Home & Kitchen' 2, 'Garden' 2, 'Sports' 4, then down to 'Electronics' 9, 'Collectibles' 9, 'Toys' 11.

Common follow-up questions