【问题标题】:Get top n counted rows in table within group [MySQL]获取组内表中的前 n 个计数行 [MySQL]
【发布时间】:2020-06-03 12:59:10
【问题描述】:

我正在尝试仅获得按类别分组的前 3 名销售产品(按每个类别在交易 (id) count(id) 中出现的前 3 名产品)。我一直在寻找可能的解决方案,但没有结果。看起来它在 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        |
+--------+------------+-----------+

【问题讨论】:

    标签: mysql sql group-by greatest-n-per-group


    【解决方案1】:

    如果你运行的是 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
    )
    

    【讨论】:

    • 不幸的是FUNCTION rank does not exists 所以我需要找到一些解决方法
    • @kpl92:我用早期版本的解决方案更新了我的答案。
    • 是的,但我不知道为什么我没有得到任何结果
    【解决方案2】:

    在早期版本的 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;
    

    【讨论】:

    • 是的,您的查询在我的 MySQL 版本中运行良好。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2020-03-01
    • 2011-04-12
    • 1970-01-01
    • 2015-03-10
    • 2020-10-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    相关资源
    最近更新 更多