• SQL之分组排序取top n


    转自:http://blog.csdn.net/wguangliang/article/details/50167283

    要求:按照课程分组,查找每个课程最高的两个成绩。

    数据文件如下:

    第一列no为学号,第二列course为课程,第三列score为分数

    [plain] view plain copy

    1. mysql> select * from lesson; 

    2. +-------+---------+-------+ 

    3. | no    | course  | score | 

    4. +-------+---------+-------+ 

    5. | N0101 | Marth   |   100 | 

    6. | N0102 | English |    12 | 

    7. | N0102 | Chinese |    55 | 

    8. | N0102 | History |    58 | 

    9. | N0102 | Marth   |    25 | 

    10. | N0103 | English |   100 | 

    11. | N0103 | Chinese |    87 | 

    12. | N0103 | History |    88 | 

    13. | N0103 | Marth   |    72 | 

    14. | N0104 | English |    20 | 

    15. | N0104 | Chinese |    60 | 

    16. | N0104 | History |    88 | 

    17. | N0104 | Marth   |    56 | 

    18. | N0105 | English |    56 | 

    19. | N0105 | Chinese |    88 | 

    20. | N0105 | History |    88 | 

    21. | N0201 | English |    66 | 

    22. | N0201 | Chinese |    77 | 

    23. | N0201 | History |    80 | 

    24. | N0201 | Marth   |   100 | 

    25. | N0202 | English |    35 | 

    26. | N0202 | Chinese |    56 | 

    27. | N0202 | History |    86 | 

    28. | N0202 | Marth   |    99 | 

    29. | N0203 | English |   100 | 

    30. | N0203 | Chinese |    87 | 

    31. | N0203 | History |    88 | 

    32. | N0203 | Marth   |    57 | 

    33. | N0204 | English |    98 | 

    34. | N0204 | Chinese |   100 | 

    35. | N0204 | History |    66 | 

    36. | N0204 | Marth   |    71 | 

    37. | N0205 | English |    98 | 

    38. | N0205 | Chinese |   100 | 

    39. | N0205 | History |    66 | 

    40. | N0205 | Marth   |    71 | 

    41. | N0301 | English |    66 | 

    42. | N0301 | Chinese |    89 | 

    43. | N0301 | History |    68 | 

    44. | N0301 | Marth   |    83 | 

    45. | N0302 | English |    76 | 

    46. | N0302 | Chinese |    99 | 

    47. | N0302 | History |    80 | 

    48. | N0302 | Marth   |    74 | 

    49. | N0303 | English |   100 | 

    50. | N0303 | Chinese |   100 | 

    51. | N0303 | History |    88 | 

    52. | N0303 | Marth   |    57 | 

    53. | N0304 | English |    76 | 

    54. | N0304 | Chinese |   100 | 

    55. | N0304 | History |    66 | 

    56. | N0304 | Marth   |    86 | 

    57. | N0305 | English |    98 | 

    58. | N0305 | Chinese |   100 | 

    59. | N0305 | History |    40 | 

    60. | N0305 | Marth   |    59 | 

    61. | N0306 | English |    52 | 

    62. | N0306 | Chinese |    87 | 

    63. | N0306 | History |    72 | 

    64. | N0306 | Marth   |    71 | 

    65. | N0101 | Chinese |    55 | 

    66. | N0101 | History |    84 | 

    67. | N0101 | English |    82 | 

    68. | N0101 | English |    82 | 

    69. +-------+---------+-------+ 

    70. 64 rows in set 

    在hive上查询

    1. select a.course,a.score 

    2. from

    3. ( 

    4. select course,score,row_number() over(partition by course order by score desc) as

    5. from lesson

    6. )a 

    7. where a.n<=2;  

    其中:

    1. row_number() over(partition by course order by score desc

    意思是以课程分组,按成绩递减排序,并为每组中的数据打上行号的标记,从1开始。

    这样,再在外层套一层过滤行号小于等于2的即可:-D

    查询结果如下图1所示:

    wpsC794.tmp

    图1 Hive查询结果

    在mysql上查询

    由于MySQL不支持row_number()over()等窗口函数

    方法1.自查询比较

    1. select course,score 

    2. from lesson a 

    3. where 2 > 

    4. ( 

    5. select count(1) 

    6. from lesson b 

    7. where a.score<b.score and a.course=b.course 

    8. ) 

    9. order by a.course,a.score desc

    因为是查询最高的两个成绩,所以是2>,如果查询最高的前N个成绩,改成 N>

    该条sql语句的大概思路是:

    从a表中拿出一条数据,与b表中所有与该条数据相同course的数据比较,统计出b表有多少相同课程的score比该条数据的score高;

    如果b表中有0条比该条数据高,则该条数据是该门课程的最高分;

    如果统计出有1条数据,则该条数据是该门课程分数的第二高;

    但是,还存在一些问题:

    比如,最高分存在多个,则会统计出多于2条的数据,如下图2统计结果也有所反应:

    wpsC795.tmp

    图2 mysql查询结果

    方法2.动态sql

    1. SET @row=0; 

    2. SET @groupid=''; 

    3. select a.course,a.score 

    4. from

    5. ( 

    6. select no,course,score,case when @groupid=course then @row:=@row+1 else @row:=1 end rownum,@groupid:=course from lesson 

    7. order by course,score desc

    8. )a 

    9. where a.rownum<=2; 

    其中:

    @row用于统计行号,@groupid用于分组,记录该组的名称

    1. select no,course,score,case when @groupid=course then @row:=@row+1 else @row:=1 end rownum,@groupid:=course from lesson 

    2. order by course,score desc

    意思是:按照分组名course和需要的排序score递增 进行排序,这样,相同课程就会排在一起,且相同的课程之间按照成绩排序。

    取出一条数据,如果该条数据的course与@group相同,则意味着是相同课程之间的比较,那么@row自加1。

    否则意味着该条数据是另一门课程的第一条数据,则@row=1

    这样每个课程就能够按照成绩排序并标记上行号

    那么外层只需要过滤rownum<=2即可得到每门课的前2个最高分。

    最后执行结果与hive一致,不再上图片了。

  • 相关阅读:
    redis特性,使用场景
    docker 界面话管理工具Portainer
    解决streamsets jdbc全量模式数据重复问题
    clickhouse 行列转换
    clickHouse 常用命令
    mysqldump导出数据
    oracle 迁移到clickhouse 45亿条数据
    clickHouse 导入/删除/更新数据
    clickhouse Mysql 数据类型对比
    maven 的使用
  • 原文地址:https://www.cnblogs.com/wcwen1990/p/7601213.html
Copyright © 2020-2023  润新知