Revenue Rank per Category
Rank products by revenue within category.
The challenge runs on the SQLabHub practice database (SQLite) and uses the products and order_items tables. You can solve it in the browser, with nothing to install.
The task
Rank products by revenue within category.
A correct answer returns 119 rows with 4 columns: category, id, revenue, rnk.
Tables used in this challenge
products 120 rows
id INTEGER (PK) · name TEXT · category TEXT · price REAL · cost REAL · stock INTEGER · sku TEXT · status TEXT · rating REAL · review_count INTEGER
| id | name | category | price | cost | stock | sku | status | rating | review_count |
|---|---|---|---|---|---|---|---|---|---|
order_items 496 rows
id INTEGER (PK) · order_id INTEGER · product_id INTEGER · quantity INTEGER · unit_price REAL · subtotal REAL
| id | order_id | product_id | quantity | unit_price | subtotal |
|---|---|---|---|---|---|
The first rows of each table are shown. See how all the tables relate on the database schema page.
Expected output
| category | id | revenue | rnk |
|---|---|---|---|
First 5 of 119 rows. This is the output of the model solution on the practice database. The task does not fix a sort order, so your rows may come back in a different order.
What you practise
- Summarising many rows into one value with COUNT, SUM, AVG, MIN or MAX
- Grouping by more than one column to get a row per combination
- Combining rows from two tables on a matching key with an inner join
- Querying the result of another query with a subquery in FROM
- Ranking rows with RANK() or DENSE_RANK() and handling ties
- Restarting a window calculation for each group with PARTITION BY
Hint and approach
Try the challenge first. Open these only when you need them.
Show the hint
SUM + RANK
Show the step-by-step approach
How the model solution is built, in the order the database evaluates it:
- Build an inner query first (a derived table):
- Read from the
productstable. - Join
order_itemsonproducts.id=order_items.product_id. - Group the rows by
products.categoryandproducts.id, so the result has one row for each combination. - For each group, compute
SUM(order_items.subtotal).
- Read from the
- Rank the rows with
RANK(), ordered byrevenuedescending, restarting for eachcategory. Tied rows share a rank and the next rank is skipped.
Model solution
Checking your session…
What to watch for
- RANK() and DENSE_RANK(). RANK() skips numbers after a tie (1, 1, 3) and DENSE_RANK() does not (1, 1, 2). Filtering on rank <= N returns more than N rows when there are ties.
- PARTITION BY. PARTITION BY is not GROUP BY: it keeps every row and only decides which rows a window function looks at.
- Derived table. Columns computed in the inner query are only visible outside under their alias, so every calculated column there needs a name.
Related SQL challenges
- Find the Top 2 Products by Revenue in Each CategorySimilar levelHard
- Rank Products by Price Within Each CategorySimilar levelHard
- Calculate Revenue and Units Sold per Product CategoryEasierMedium
- Calculate Month-over-Month Revenue Change per ProductSimilar levelHard
- Find the Top-Spending Customer in Each CountrySimilar levelHard
Keep learning
- Lesson: RANK & DENSE_RANK
- Lesson: Window Functions
- Lesson: SQL Subqueries
- Lesson: INNER JOIN
- All SQL practice challenges, by difficulty and topic
- SQL interview questions with answers
- SQL Playground: run any query on the same database