Получить первые n подсчитанных строк в таблице в группе [MySQL] - PullRequest
0 голосов
/ 19 февраля 2020

Я пытаюсь получить только топ-3 продаваемых товаров, сгруппированных по категориям (только топ-3 товара по вхождению в транзакции (id) count(id) по каждой категории). Я много искал возможного решения, но безрезультатно. Похоже, это немного сложно в MySQL, так как нельзя просто использовать функцию top () и так далее. Пример структуры данных ниже:

+--------+------------+-----------+
|     id |category_id | product_id|
+--------+------------+-----------+
| 1      | 10         | 32        |
| 2      | 10         | 34        |
| 3      | 10         | 32        |
| 4      | 10         | 21        |
| 5      | 10         | 100       |
| 6      | 7          | 101       |
| 7      | 7          | 39        |
| 8      | 7          | 41        |
| 9      | 7          | 39        |
+--------+------------+-----------+

Ответы [ 2 ]

1 голос
/ 19 февраля 2020

В более ранних версиях MySQL я бы рекомендовал использовать переменные:

select cp.*
from (select cp.*,
             (@rn := if(@c = category_id, @rn + 1,
                        if(@c := category_id, 1, 1)
                       )
             ) as rn
      from (select category_id, product_id, count(*) as cnt
            from mytable
            group by category_id, product_id
            order by category_id, count(*) desc
           ) cp cross join
           (select @c := -1, @rn := 0) params
     ) cp
where rn <= 3;
1 голос
/ 19 февраля 2020

Если вы используете MySQL 8.0, вы можете использовать оконную функцию rank() для этого:

select *
from (
    select 
        category_id,
        product_id,
        count(*) cnt,
        rank() over(partition by category_id order by count(*) desc) rn
    from mytable
    group by category_id, product_id
) t
where rn <= 3

В более ранних версиях одним из вариантов является фильтрация с коррелированным подзапросом:

select 
    category_id,
    product_id,
    count(*) cnt
from mytable t
group by category_id, product_id
having count(*) >= (
    select count(*)
    from mytable t1
    where t1.category_id = t.category_id and t1.product_id = t.product_id
    order by count(*) desc
    limit 3, 1
)
...