Category Sales Summary
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
- Asked in
- Workday
Problem
A merchandising team is sizing up how each product category performs, looking only at items currently in stock. For every category with a sale, show how many different products it sold and the total revenue they brought in, highest revenue first.
Category by category. How did they do?
Tables
transactions
Columns: transaction_id INTEGER, user_id INTEGER, product_id INTEGER, quantity INTEGER, total_amount REAL, transaction_date TEXT
| transaction_id | user_id | product_id | quantity | total_amount | transaction_date |
|---|---|---|---|---|---|
| 1067 | 197 | 1001 | 2 | 23.46 | 2026-02-02 |
| 1134 | 294 | 1050 | 3 | 36.93 | 2026-03-03 |
| 1201 | 391 | 1099 | 4 | 50.4 | 2026-04-04 |
| 1268 | 488 | 1148 | 5 | 63.87 | 2026-05-05 |
| 1335 | 585 | 1197 | 0 | 0 | 2026-06-06 |
| 1402 | 682 | 1246 | 2 | 90.81 | 2026-07-07 |
| 1469 | 779 | 1295 | 3 | 104.28 | 2026-08-08 |
| 1536 | 876 | 1344 | 4 | 117.75 | 2026-09-09 |
| 1603 | 973 | 1393 | 5 | -45 | 2026-01-10 |
| 1670 | 1070 | 1442 | 1 | 144.69 | 2026-02-11 |
products
Columns: product_id INTEGER, product_name TEXT, category TEXT, price REAL, rating REAL, in_stock INTEGER
| product_id | product_name | category | price | rating | in_stock |
|---|---|---|---|---|---|
| 1001 | Basic Device 1X | Books | 17.52 | 2.7 | 1 |
| 1050 | Deluxe Bundle 2X | Clothing | 25.05 | 4.4 | 1 |
| 1099 | Pro Unit 3X | Home & Kitchen | 32.58 | 2.1 | 1 |
| 1148 | Ultra Tool 4X | Collectibles | 40.11 | 3.8 | 1 |
| 1197 | Essential Set 5X | Toys | 47.64 | 1.5 | 1 |
| 1246 | Classic System 6X | Beauty | 0 | 3.2 | 1 |
| 1295 | Smart Gadget 7X | Automotive | 62.7 | 4.9 | 0 |
| 1344 | Eco Kit 8X | Garden | 70.23 | 2.6 | 1 |
| 1393 | Turbo Pack 9X | Music | 77.76 | 4.3 | 0 |
| 1442 | Premium Widget 10X | Electronics | 85.29 | 2 | 1 |
Expected output
| category | products_sold | total_revenue |
|---|---|---|
| Electronics | 9 | 13111.02 |
| Automotive | 8 | 11666.7 |
| Books | 7 | 9444.15 |
| Sports | 6 | 9387.24 |
| Collectibles | 1 | 127.74 |
Worked solution and explanation
What this really is
This is a distinct-product count wearing a sales-report costume. The skill being probed: can you count PRODUCTS, not sales, per category while summing money in the same pass and keeping discontinued lines out? Anyone can join transactions to products and group by category. The trap is the product figure: a popular product gets bought over and over, so a plain COUNT of the joined rows counts that product once per receipt. Reach for COUNT(*) and your 'products' number is really a sales number, and the categories carrying a few hot repeat-sellers balloon up the leaderboard for no real reason. Miss the in-stock filter and you also fold discontinued items' revenue back into the totals.
Working it out
Step 1: Join, then drop out-of-stock lines
Join transactions to products on product_id so every sale carries its category, then keep only in-stock items with p.in_stock = 1. That filter matters more than it looks: out-of-stock products still have historical transactions, so with no filter you quietly add discontinued lines back into both the product count and the revenue.
Step 2: Dedup the products, total the money
Group by p.category. Use COUNT(DISTINCT t.product_id) for products so a hot seller bought many times still counts as one product, and SUM(t.total_amount) for revenue so you total the amount actually charged rather than recomputing price times quantity.
Step 3: Sort by revenue, let the join filter
ORDER BY total_revenue DESC floats the strongest categories to the top, which is the only order the ask names. There is no HAVING to write: an inner join means a category with no sale never appears, which is exactly the 'made a sale' rule.
The solution
SELECT
p.category,
COUNT(DISTINCT t.product_id) AS products_sold,
SUM(t.total_amount) AS total_revenue
FROM transactions t
JOIN products p ON t.product_id = p.product_id
WHERE p.in_stock = 1
GROUP BY p.category
ORDER BY total_revenue DESCCommon follow-up questions
- How would you also list categories that sold nothing, showing zero products and zero revenue? (Forces LEFT JOIN from products grouped by category with COALESCE on the aggregates.)
- If a category's top product just went out of stock, what happens to its revenue rank here? (Probes whether they see that revenue and product counts move independently under the in-stock filter.)
- How would you also report the number of different customers per category alongside the product count? (Tests whether they can add a second dedup dimension without double-counting.)