1

I have 3 tables: product, category and product_category (which products are in each category).

I'd like to get the top 3 most expensive product in each category.

I have this basic relation:

select c.name
     , p.id
     , p.price 
  from category c
  left 
  join product_category pc
    on pc.category_id = category.id
  left 
  join product p 
    on pc.product_id = p.id

But now I would like to get just the 3 most expensive of each category.

In this case we can use any number of joined tables and it can be escalated to any more complex query.

Is this possible without a loop ?

I'm using 10.2.14-MariaDB-log with this schema http://sqlfiddle.com/#!9/43035a

Kamil Gosciminski
  • 16,547
  • 8
  • 49
  • 72
FlamingMoe
  • 2,709
  • 5
  • 39
  • 64

1 Answers1

2

MySQL 8.0+ & MariaDB 10.2+ support window functions like dense_rank which are suited to handle your case. For each category we assign ranks based on product price and pull only those, who are in the top 3. Use of dense_rank properly handles ties which means that if there are products for a category with the same price there can be more than 3 rows in the output for a particular category. If this behaviour is not the preferred one and you would rather want to see max 3 rows in the output, discarding ties, use row_number window function instead.

select name, id
from (
  select c.name, p.id, dense_rank() over (partition by c.id order by p.price desc) as rank
  from category c
  left join product_category pc on pc.category_id = c.id
  left join product p on pc.product_id = p.id
) t
where rank <= 3
Kamil Gosciminski
  • 16,547
  • 8
  • 49
  • 72