V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 外包信息请发到 /go/outsourcing 节点。
• 不要把相同的信息发到不同的节点
vegetableChick
V2EX  ›  酷工作

MYSQL 求每个月的 topN 问题

  •  
  •   vegetableChick · 2021-03-29 11:33:29 +08:00 · 2460 次点击
    这是一个创建于 1360 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有如下的一个表

    months  contact   COUNT
    202007  asdas      45
    202007  maouse      1
    202007  RORC YANG   1
    202007  RORG        2
    202007  ROR         5
    202008  SARINA      6
    202008  MBL         2
    202008  MLT         2
    ...
    

    我如何能获取到每个月的top2?

    希望得到的结果:

    months  contact   COUNT
    202007  asdas      45
    202007  ROR         5
    202008  SARINA      6
    202008  MBL         2
    ...
    

    当前 mysql 版本 5.6

    请各位大佬帮忙看一下, 感谢!

    18 条回复    2021-03-31 12:59:16 +08:00
    uselessVisitor
        1
    uselessVisitor  
       2021-03-29 14:25:46 +08:00
    select * from a A where (select cout(*) from a B where A.months = B.months and A.count >= B.count) <= 2
    uselessVisitor
        2
    uselessVisitor  
       2021-03-29 14:26:26 +08:00
    count(*) 拼错了,还有你发错分区了吧。。
    Nostalgiaaaa
        3
    Nostalgiaaaa  
       2021-03-29 14:29:32 +08:00
    SELECT *
    FROM
    (SELECT *,
    ROW_NUMBER() over(partition by months
    ORDER BY COUNT desc) ranks
    FROM table ) a
    WHERE a.ranks IN (1, 2)
    ahmcsxcc
        4
    ahmcsxcc  
       2021-03-29 14:31:25 +08:00
    @Nostalgiaaaa #3 mysql 5.6 不支持这个语法
    uselessVisitor
        5
    uselessVisitor  
       2021-03-29 15:32:25 +08:00
    @ahmcsxcc 是的,mysql 这个需求比较难弄啊,感觉要写存储过程。。不然就要在代码里写了。。还是 PgSql 函数多
    vegetableChick
        6
    vegetableChick  
    OP
       2021-03-29 15:32:56 +08:00
    @beichenhpy 感谢回复, 但是好像是空结果
    vegetableChick
        7
    vegetableChick  
    OP
       2021-03-29 15:33:31 +08:00
    @Nostalgiaaaa 谢谢回复, 我的 mysql 版本比较旧了 还是 5.6
    uselessVisitor
        8
    uselessVisitor  
       2021-03-29 16:03:17 +08:00
    @vegetableChick
    -- part 为 month 对应用谁分组
    select z.month,z.count,z.rank
    from
    (select
    x.*,
    @rownum := @rownum + 1,
    if(@part = x.month,
    @r := @r + 1,
    @r := 1) as rank,
    @part := x.month
    from
    (
    select
    *
    from
    test e
    order by
    e.count,e.`month` desc) x,
    (
    select
    @rownum := 0,
    @part := null,
    @r := 0) rt)z
    where z.rank in (1,2)
    uselessVisitor
        9
    uselessVisitor  
       2021-03-29 16:15:21 +08:00
    @vegetableChick
    ```
    -- part 为 month 对应用谁分组
    -- 注意 order by 的顺序
    select z.month,z.count,z.rank
    from
    (select
    x.*,
    @rownum := @rownum + 1,
    if(@part = x.month,@r := @r + 1,@r := 1) as rank,
    @part := x.month
    from
    (
    select
    *
    from
    test e
    order by
    e.month asc,e.count desc) x,
    (
    select
    @rownum := 0,
    @part := null,
    @r := 0) rt)z
    where z.rank in (1,2)
    ```
    vegetableChick
        10
    vegetableChick  
    OP
       2021-03-29 16:29:59 +08:00
    @beichenhpy nb !但是没太看懂, 求大佬讲一下思路
    vegetableChick
        11
    vegetableChick  
    OP
       2021-03-29 16:30:36 +08:00
    @beichenhpy 结果出来了, 但是没懂原理
    uselessVisitor
        12
    uselessVisitor  
       2021-03-29 16:41:35 +08:00
    @vegetableChick 就是实现了一遍 over(partition by month)
    vegetableChick
        13
    vegetableChick  
    OP
       2021-03-29 16:48:30 +08:00
    @beichenhpy 我怎么老觉得不需要 下面的这个`select`, 看上去上面把这些变量又初始化了。 但是去掉就错了
    ```
    select
    @rownum := 0,
    @part := null,
    @r := 0) rt)z
    ```
    uselessVisitor
        14
    uselessVisitor  
       2021-03-29 16:49:04 +08:00
    @vegetableChick 下面是初始化的。。不要去掉
    uselessVisitor
        15
    uselessVisitor  
       2021-03-29 16:49:58 +08:00
    @vegetableChick 看一下 mysql 执行顺序。。from 是先执行的
    vegetableChick
        16
    vegetableChick  
    OP
       2021-03-29 16:56:56 +08:00
    @beichenhpy 嗯 感谢,学习一下
    more1sec
        17
    more1sec  
       2021-03-29 17:43:47 +08:00
    程序代码处理吧。。。别用子查询
    zzz686970
        18
    zzz686970  
       2021-03-31 12:59:16 +08:00
    @beichenhpy
    我测试了一下,子查询里面应该是小于?而且如果 count 有重复的数字,应该换成<

    ```
    select * from t A where (select count(*) from t B where A.month = B.month and A.cnt < B.cnt) < 2

    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5028 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 03:50 · PVG 11:50 · LAX 19:50 · JFK 22:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.