The Heavy Hitters

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
L4
Asked in
Amazon

Problem

An analyst suspects the catalog only looks diverse and that a handful of products carry most of the sales recorded in transactions, where a product's revenue is its total amount across every sale. Build her a leaderboard of the top 10 positions, each product shown with its name from products, its total, and its position on the board.

Total sales tell the real story. Surface the products that carry the catalog.

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 10 rows
product_nametotal_total_amountrnk
Premium Widget 100X2713.981
Eco Kit 98X2660.12
Smart Gadget 97X2633.163
Classic System 96X2606.224
Essential Set 95X2579.285

Worked solution and explanation

What this really is

This is a group-sum with a rank bolted on, wearing a leaderboard costume. Everyone totals the sales per product. The trap is reading 'top 10' as ORDER BY total DESC LIMIT 10 and stopping there: LIMIT slices rows but never writes a number, so the position column the board needs simply does not exist in your output. And if you fake one with a row counter, two products with the same total get different positions and the one that lands at 11 silently falls off the board.


Building it up

Step 1: Total each product

Join transactions to products on product_id, then GROUP BY p.product_name with SUM(t.total_amount). That collapses many sales into one total per product, and names this intermediate product_revenue so the next step reads plainly.

Step 2: Assign positions

Over product_revenue, DENSE_RANK() OVER (ORDER BY total_total_amount DESC) stamps a position on each total, biggest first. Ranking the named total, not re-writing the SUM, keeps every expression defined once.

Step 3: Keep the top 10 positions

A window function cannot be filtered in the SELECT that defines it, so the ranking lives in its own CTE, ranked, and the outer query keeps rnk <= 10. That filter is on standing, so a tie at position 10 keeps every tied product.


The solution

Revenue leaderboard
WITH product_revenue AS (
    SELECT
        p.product_name,
        SUM(t.total_amount) AS total_total_amount
    FROM transactions t
    JOIN products p ON t.product_id = p.product_id
    GROUP BY p.product_name
),
ranked AS (
    SELECT
        product_name,
        total_total_amount,
        DENSE_RANK() OVER (ORDER BY total_total_amount DESC) AS rnk
    FROM product_revenue
)
SELECT product_name, total_total_amount, rnk
FROM ranked
WHERE rnk <= 10
`ROW_NUMBER()`
Say two products both total 2,606.22. They get positions 4 and 5 in whatever order the engine picks, and the next product jumps to 6. Ties are broken by luck.
`DENSE_RANK()`
Both products at 2,606.22 get position 4 and the next product is 5. Equal totals mean equal standing, and rnk <= 10 keeps or drops them together.

Common follow-up questions