我们写SQL时,经常会遇到这个逻辑,按某个字段分组然后从每组按某个字段取出最大的一条纪录,我们在oracle、mysql分别探讨一下实现的方法,现在我们开始吧。
新建一张表 exam_results
type | results | class |
---|---|---|
数学 | 23 | 一班 |
英语 | 56 | 一班 |
语文 | 12 | 一班 |
数学 | 8 | 二班 |
数学 | 78 | 三班 |
语文 | 90 | 二班 |
oracle
想得到的数据是 按照 type 分组 然后取出每组中 results 最大的那几条纪录。结果应该是这三条纪录:
type | results | class |
---|---|---|
数学 | 78 | 三班 |
英语 | 56 | 一班 |
语文 | 90 | 二班 |
方法一: 直接使用聚合函数
SELECT a.type, MAX(a.results) FROM exam_results a GROUP BY a.type
查出来的结果如下:
type | results |
---|---|
数学 | 78 |
英语 | 56 |
语文 | 90 |
这种比较简单,但是有个问题,查询结果不能展示出来class字段(其实也不能不可以,就是比较麻烦,需要修改数据库配置文件或者是用关联的手法写,均不建议),因为ONLY_FULL_GROUP_BY是MySQL数据库提供的一个sql_mode, 通过这个 sql_mode 来保证, SQL语句 “分组求最值” 合法性的检查. 这种模式采用了与 Oracle、DB2 等数据库的处理方式。即不允许 select target list 中出现语义不明确的列。对于用到 GROUP BY 的 select 语句, 查出来的列必须是 group by 后面声明的列, 或者是聚合函数里面的列有这样一个数据库的表。为了解决该问题,又找到了方法二。
方法二:使用ROW_NUMBER() OVER()函数
具体写法如下:
SELECT
*
FROM
(
SELECT a.*, row_number ( ) over ( PARTITION BY listid(按此分组) ORDER BY recid(按此排序) DESC ) rn FROM mo_partprg a
) t1
WHERE
rn = 1;
套用到我们的表结构中就是
SELECT
*
FROM
( SELECT a.*, row_number ( ) over ( PARTITION BY type ORDER BY results DESC ) rn FROM exam_results a ) t1
WHERE
rn = 1;
查出来的结果如下:
type | results | class |
---|---|---|
数学 | 78 | 三班 |
英语 | 56 | 一班 |
语文 | 90 | 二班 |
mysql
经过验证,mysql中如下
Mysql版本5.7可用oracle中方法二
Mysql版本8可用oracle中 方法一、方法二
欢迎各位大神批评指正,或者提出一些其他的更好的方法大家一起交流学习!
#@lehao#
帮助到您请点赞关注收藏谢谢!!