sql分组排序取top n
2015-12-03 23:08
836 查看
数据库查询*分组排序取top n
要求:按照课程分组,查找每个课程最高的两个成绩。数据文件如下:
第一列no为学号,第二列course为课程,第三列score为分数
mysql> select * from lesson; +-------+---------+-------+ | no | course | score | +-------+---------+-------+ | N0101 | Marth | 100 | | N0102 | English | 12 | | N0102 | Chinese | 55 | | N0102 | History | 58 | | N0102 | Marth | 25 | | N0103 | English | 100 | | N0103 | Chinese | 87 | | N0103 | History | 88 | | N0103 | Marth | 72 | | N0104 | English | 20 | | N0104 | Chinese | 60 | | N0104 | History | 88 | | N0104 | Marth | 56 | | N0105 | English | 56 | | N0105 | Chinese | 88 | | N0105 | History | 88 | | N0201 | English | 66 | | N0201 | Chinese | 77 | | N0201 | History | 80 | | N0201 | Marth | 100 | | N0202 | English | 35 | | N0202 | Chinese | 56 | | N0202 | History | 86 | | N0202 | Marth | 99 | | N0203 | English | 100 | | N0203 | Chinese | 87 | | N0203 | History | 88 | | N0203 | Marth | 57 | | N0204 | English | 98 | | N0204 | Chinese | 100 | | N0204 | History | 66 | | N0204 | Marth | 71 | | N0205 | English | 98 | | N0205 | Chinese | 100 | | N0205 | History | 66 | | N0205 | Marth | 71 | | N0301 | English | 66 | | N0301 | Chinese | 89 | | N0301 | History | 68 | | N0301 | Marth | 83 | | N0302 | English | 76 | | N0302 | Chinese | 99 | | N0302 | History | 80 | | N0302 | Marth | 74 | | N0303 | English | 100 | | N0303 | Chinese | 100 | | N0303 | History | 88 | | N0303 | Marth | 57 | | N0304 | English | 76 | | N0304 | Chinese | 100 | | N0304 | History | 66 | | N0304 | Marth | 86 | | N0305 | English | 98 | | N0305 | Chinese | 100 | | N0305 | History | 40 | | N0305 | Marth | 59 | | N0306 | English | 52 | | N0306 | Chinese | 87 | | N0306 | History | 72 | | N0306 | Marth | 71 | | N0101 | Chinese | 55 | | N0101 | History | 84 | | N0101 | English | 82 | | N0101 | English | 82 | +-------+---------+-------+ 64 rows in set
在hive上查询
select a.course,a.score from ( select course,score,row_number() over(partition by course order by score desc) as n from lesson )a where a.n<=2;
其中:
row_number() over(partition by course order by score desc)意思是以课程分组,按成绩递减排序,并为每组中的数据打上行号的标记,从1开始。
这样,再在外层套一层过滤行号小于等于2的即可:-D
查询结果如下图1所示:
图1 hive查询结果
在mysql上查询
由于mysql不支持row_number()over()等窗口函数所以/(ㄒoㄒ)/~~
方法1.自查询比较
select course,score from lesson a where 2 > ( select count(1) from lesson b where a.score<b.score and a.course=b.course ) order by a.course,a.score desc;
因为是查询最高的两个成绩,所以是2>,如果查询最高的前N个成绩,改成 N>
该条sql语句的大概思路是:
从a表中拿出一条数据,与b表中所有与该条数据相同course的数据比较,统计出b表有多少相同课程的score比该条数据的score高;
如果b表中有0条比该条数据高,则该条数据是该门课程的最高分;
如果统计出有1条数据,则该条数据是该门课程分数的第二高;
但是,还存在一些问题:
比如,最高分存在多个,则会统计出多于2条的数据,如下图2统计结果也有所反应:
图2 mysql查询结果
方法2.动态sql
SET @row=0; SET @groupid=''; select a.course,a.score from ( select no,course,score,case when @groupid=course then @row:=@row+1 else @row:=1 end rownum,@groupid:=course from lesson order by course,score desc )a where a.rownum<=2;
其中:
@row用于统计行号,@groupid用于分组,记录该组的名称
select no,course,score,case when @groupid=course then @row:=@row+1 else @row:=1 end rownum,@groupid:=course from lesson order by course,score desc
意思是:按照分组名course和需要的排序score递增 进行排序,这样,相同课程就会排在一起,且相同的课程之间按照成绩排序。
取出一条数据,如果该条数据的course与@group相同,则意味着是相同课程之间的比较,那么@row自加1。
否则意味着该条数据是另一门课程的第一条数据,则@row=1
这样每个课程就能够按照成绩排序并标记上行号
那么外层只需要过滤rownum<=2即可得到每门课的前2个最高分。
最后执行结果与hive一致,不再上图片了。
相关文章推荐
- 01.Django学习之安装,建立项目,传参,MySQL数据库,静态文件配置和模板的使用
- PLSQL Developer连接数据库(64位操作系统)
- Oracle12c及PLSQL Developer安装全程记录
- unqlite安装/使用/测试
- win8 64位使用plsql developer连接oracle数据库问题
- Can't open the mysql.plugin table. Please run mysql_upgrade to create it
- MySQL 高可用架构之MMM
- GoLang操作Mysql
- zabbix实现mysql数据库的监控(四)
- 运维角度浅谈MySQL数据库优化
- Incorrect key file for table '/tmp/....'错误的解决--记录
- MySql的架构和历史
- PL/SQL Developer 开发工具修改日期类型的值
- sqlite3.OperationalError: unrecognized token: ":"
- plsqldeveloper客户端字符集和数据库服务器端(AL32UFT8)不一致
- 对比SQL 学 mongo
- 解决【2006 - MySQL server has gone away】问题
- PL/SQL Developer记住用户名密码
- Mysql监控方法之一
- Django models通过DateTimeField保存到MySQL的时间的时区问题