Brightlane's category manager ranks products within each category by price from highest to lowest.
Write a query to return the ID, name, category ID, and price of every product, plus the product's rank within its category by price in descending order.
Assumptions:
- The
productstable has one row per product with anid, aname, acategory_id, and aprice. - Within each category, rank
1goes to the highest-priced product. Rank values restart for each category. - Products with the same
pricein the same category receive the same rank, with the next rank adjusted upward by the number of tied products.
Output:
- One row per product, with columns
id,name,category_id,price, andcategory_price_rank.
Schema · ecommerce 5 tables
Run previews · Check grades
Write a query, then run it to see results here.
Worked solution Try it yourself first
SELECT
id,
name,
category_id,
price,
RANK() OVER (
PARTITION BY
category_id
ORDER BY
price DESC
) AS category_price_rank
FROM
products The shape
RANK() OVER (PARTITION BY category_id ORDER BY price DESC) runs an independent price ranking inside each category. The most expensive product in a category gets 1 no matter what the global top price is, and ties on price within a category produce shared ranks followed by a gap.
Clause by clause
SELECT id, name, category_id, price, RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS category_price_rankreturns each product's identifying columns and its rank inside its category.PARTITION BY category_idseparates the catalog into one window per category;ORDER BY price DESCsorts within each category from most to least expensive;RANKassigns rank1to the top product (or products) in each category.FROM productsreads every product. No filter; every product receives a per-category rank.
Why RANK and not DENSE_RANK
DENSE_RANK would also produce per-category rankings, but it would not gap after a tie. If a category has two products tied at the top price, RANK returns 1, 1, 3, ... and DENSE_RANK returns 1, 1, 2, .... The brief asks for a "price rank" where the gap is informative: a product at rank 5 in its category has four strictly-pricier products above it. DENSE_RANK would obscure that signal by collapsing tied positions.
The trap
The rank resets at every category_id boundary, which means a product showing category_price_rank = 1 is not the most expensive in the catalog; it is the most expensive in its category. Reading the output without keeping the partition column in mind is the easy mistake. Always carry category_id (or whatever column the partition is on) in the SELECT list so the rank is interpretable.
You practiced RANK() OVER (PARTITION BY ... ORDER BY ...) — tie-aware ranking that restarts within each partition; gaps appear after every tie.