MySQL获取分组后的TOP 1和TOP N记录

有时会碰到一些需求,查询分组后的最大值,最小值所在的整行记录或者分组后的top n行的记录,在一些别的数据库可能有窗口函数可以方面的查出来,但是MySQL没有这些函数,没有直接的方法可以查出来,可通过以下的方法来查询。

准备工作

测试表结构如下:

  1. root:test> show create table test1\G
  2. *************************** 1. row ***************************
  3. Table: test1
  4. Create Table: CREATE TABLE `test1` (
  5. `id` int(11) NOT NULL AUTO_INCREMENT,
  6. `name` varchar(20) DEFAULT NULL,
  7. `course` varchar(20) DEFAULT NULL,
  8. `score` int(11) DEFAULT NULL,
  9. PRIMARY KEY (`id`)
  10. ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8
  11. 1 row in set (0.00 sec)

插入数据:

  1. insert into test1(name,course,score)
  2. values
  3. ('张三','语文',80),
  4. ('李四','语文',90),
  5. ('王五','语文',93),
  6. ('张三','数学',77),
  7. ('李四','数学',68),
  8. ('王五','数学',99),
  9. ('张三','英语',90),
  10. ('李四','英语',50),
  11. ('王五','英语',89);

查看结果:

  1. root:test> select * from test1;
  2. +----+--------+--------+-------+
  3. | id | name | course | score |
  4. +----+--------+--------+-------+
  5. | 1 | 张三 | 语文 | 80 |
  6. | 2 | 李四 | 语文 | 90 |
  7. | 3 | 王五 | 语文 | 93 |
  8. | 4 | 张三 | 数学 | 77 |
  9. | 5 | 李四 | 数学 | 68 |
  10. | 6 | 王五 | 数学 | 99 |
  11. | 7 | 张三 | 英语 | 90 |
  12. | 8 | 李四 | 英语 | 50 |
  13. | 9 | 王五 | 英语 | 89 |
  14. +----+--------+--------+-------+

TOP 1

查询每门课程分数最高的学生以及成绩

1、使用自连接【推荐】

  1. root:test> select a.name,a.course,a.score from
  2. -> test1 a
  3. -> join (select course,max(score) score from test1 group by course) b
  4. -> on a.course=b.course and a.score=b.score;
  5. +--------+--------+-------+
  6. | name | course | score |
  7. +--------+--------+-------+
  8. | 王五 | 语文 | 93 |
  9. | 王五 | 数学 | 99 |
  10. | 张三 | 英语 | 90 |
  11. +--------+--------+-------+
  12. 3 rows in set (0.00 sec)

2、使用相关子查询

  1. root:test> select name,course,score from test1 a
  2. -> where score=(select max(score) from test1 where a.course=test1.course);
  3. +--------+--------+-------+
  4. | name | course | score |
  5. +--------+--------+-------+
  6. | 王五 | 语文 | 93 |
  7. | 王五 | 数学 | 99 |
  8. | 张三 | 英语 | 90 |
  9. +--------+--------+-------+
  10. 3 rows in set (0.00 sec)

或者

  1. root:test> select name,course,score from test1 a
  2. -> where not exists(select 1 from test1 where a.course=test1.course and a.score < test1.score);
  3. +--------+--------+-------+
  4. | name | course | score |
  5. +--------+--------+-------+
  6. | 王五 | 语文 | 93 |
  7. | 王五 | 数学 | 99 |
  8. | 张三 | 英语 | 90 |
  9. +--------+--------+-------+
  10. 3 rows in set (0.00 sec)

TOP N

N>=1

查询每门课程前两名的学生以及成绩

1、使用union all

如果结果集比较小,可以用程序查询单个分组结果后拼凑,也可以使用union all

  1. root:test> (select name,course,score from test1 where course='语文' order by score desc limit 2)
  2. -> union all
  3. -> (select name,course,score from test1 where course='数学' order by score desc limit 2)
  4. -> union all
  5. -> (select name,course,score from test1 where course='英语' order by score desc limit 2);
  6. +--------+--------+-------+
  7. | name | course | score |
  8. +--------+--------+-------+
  9. | 王五 | 语文 | 93 |
  10. | 李四 | 语文 | 90 |
  11. | 王五 | 数学 | 99 |
  12. | 张三 | 数学 | 77 |
  13. | 张三 | 英语 | 90 |
  14. | 王五 | 英语 | 89 |
  15. +--------+--------+-------+
  16. 6 rows in set (0.01 sec)

2、自身左连接

  1. root:test> select a.name,a.course,a.score
  2. -> from test1 a left join test1 b on a.course=b.course and a.score<b.score
  3. -> group by a.name,a.course,a.score
  4. -> having count(b.id)<2
  5. -> order by a.course,a.score desc;
  6. +--------+--------+-------+
  7. | name | course | score |
  8. +--------+--------+-------+
  9. | 王五 | 数学 | 99 |
  10. | 张三 | 数学 | 77 |
  11. | 张三 | 英语 | 90 |
  12. | 王五 | 英语 | 89 |
  13. | 王五 | 语文 | 93 |
  14. | 李四 | 语文 | 90 |
  15. +--------+--------+-------+
  16. 6 rows in set (0.00 sec)

3、相关子查询

  1. root:test> select *
  2. -> from test1 a
  3. -> where 2>(select count(*) from test1 where course=a.course and score>a.score)
  4. -> order by a.course,a.score desc;
  5. +----+--------+--------+-------+
  6. | id | name | course | score |
  7. +----+--------+--------+-------+
  8. | 6 | 王五 | 数学 | 99 |
  9. | 4 | 张三 | 数学 | 77 |
  10. | 7 | 张三 | 英语 | 90 |
  11. | 9 | 王五 | 英语 | 89 |
  12. | 3 | 王五 | 语文 | 93 |
  13. | 2 | 李四 | 语文 | 90 |
  14. +----+--------+--------+-------+
  15. 6 rows in set (0.01 sec)

4、使用用户变量

  1. root:test> set @num := 0, @course := '';
  2. Query OK, 0 rows affected (0.00 sec)
  3.  
  4. root:test>
  5. root:test> select name, course, score
  6. -> from (
  7. -> select name, course, score,
  8. -> @num := if(@course = course, @num + 1, 1) as row_number,
  9. -> @course := course as dummy
  10. -> from test1
  11. -> order by course, score desc
  12. -> ) as x where x.row_number <= 2;
  13. +--------+--------+-------+
  14. | name | course | score |
  15. +--------+--------+-------+
  16. | 王五 | 数学 | 99 |
  17. | 张三 | 数学 | 77 |
  18. | 张三 | 英语 | 90 |
  19. | 王五 | 英语 | 89 |
  20. | 王五 | 语文 | 93 |
  21. | 李四 | 语文 | 90 |
  22. +--------+--------+-------+
  23. 6 rows in set (0.00 sec)
  24.  
  25. ORACLE 可以使用排序函数
  1. select *
  2. from (select row_number() over(partition by course order by score desc) rn,
  3. t.*
  4. from TEST1 t) a
  5. where a.rn <= 2

  

  1.  

获取分组后的TOP 1和TOP N记录的更多相关文章

  1. SQL获取分组后取某字段最大一条记录(求每个类别中最大的值的列表)

    获取分组后取某字段最大一条记录 方法一:(效率最高) select * from test as a where typeindex = (select max(b.typeindex) from t ...

  2. MySQL获取分组后的TOP 1和TOP N记录-转

    有时会碰到一些需求,查询分组后的最大值,最小值所在的整行记录或者分组后的top n行的记录,在一些别的数据库可能有窗口函数可以方面的查出来,但是MySQL没有这些函数,没有直接的方法可以查出来,可通过 ...

  3. 记一次有意思的 SQL 实现 → 分组后取每组的第一条记录

    开心一刻 今天,朋友气冲冲的走到我面前 朋友:我不是谈了个女朋友,谈了三个月嘛,昨天我偷看她手机,你猜她给我备注什么 我:备注什么? 朋友:舔狗 2 号! 我一听,气就上来了,说道:走,找她去,这婆娘 ...

  4. Mysql相关子查询&&MySQL获取分组后的TOP N记录

    小燕子,哈哈哈哈~~~~~~~~~~ 相关子查询是指引用了外部查询列的子查询,即子查询会对外部查询的每行进行一次计算. 举个例子 root:test> show create table tes ...

  5. 【转】Mysql相关子查询&&MySQL获取分组后的TOP N记录

    https://www.cnblogs.com/Yiran583/p/6743870.html select * from test1 a where 2 > (select count(*) ...

  6. 获取分组后统计数量最多的纪录;limit用法;sql执行顺序

    CREATE TABLE emp(id INT PRIMARY KEY,NAME VARCHAR(11),dep_id INT ,salary INT); CREATE TABLE dept(id I ...

  7. MySQL 取分组后每组的最新记录

    修改<常用SQL之日期格式化和查询重复数据>中表test1的创建时间,修改后的测试数据如下: 以姓名分组后提取每组最新创建的记录: SELECT a.* FROM test1 AS a, ...

  8. SQL Server 分组后取Top N

    SQL Server 分组后取Top N(转) 近日,工作中突遇一需求:将一数据表分组,而后取出每组内按一定规则排列的前N条数据.乍想来,这本是寻常查询,无甚难处.可提笔写来,终究是困住了笔者好一会儿 ...

  9. SQL 分组后获取其中一个字段最大值的整条记录

    --有id,name,createDate的一张表testTable--根据name分组,获取每组中createDate最大的那条记录(整条)查询出来------------------------- ...

随机推荐

  1. BZOJ3172 & 洛谷3966 [Tjoi2013]单词 【fail树】

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 4293  Solved: 2083 [Submit][Stat ...

  2. 从零开始学Linux系统(四)之Vi/Vim操作指令

    模式切换: 编辑模式 <-- [:]<--命令模式 -->[a.i.o A.I.O]-->  插入模式 编辑模式操作: 设置行号  :set nu   :set nonu 复制 ...

  3. 洛谷P1667/[10.22 模拟赛] 数列 (思维+模拟)

    洛谷P1667 数列 题目描述 给定一个长度是n的数列A,我们称一个数列是完美的,当且仅当对于其任意连续子序列的和都是正的.现在你有一个操作可以改变数列,选择一个区间[X,Y]满足\(A_X +A_{ ...

  4. bzoj 相似回文串 3350 3103 弦图染色+manacher

    相似回文串 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 143  Solved: 68[Submit][Status][Discuss] Descr ...

  5. SDUT3926 kmp

    bLue的二叉树 Time Limit: 3000MS Memory Limit: 65536KB Submit Statistic Problem Description Keke 是一个喜爱种树的 ...

  6. HDU1711 KMP(模板题)

    Number Sequence Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  7. Linux网络监控工具nethogs

    Linux网络监控工具nethogs 标签: 监控工具linux 2015-12-17 22:06 448人阅读 评论(0) 收藏 举报  分类: linux(40)  版权声明:本文为博主原创文章, ...

  8. Moodle通过CLI安装

    Moodle通过CLI安装 前提:Moodle准备工作已经完成 1) 数据库(及用户) 2) moodledata目录 3) 源代码及站点配置 安装过程 打开终端,或通过Putty或Xshell等软件 ...

  9. (转)史上最好的Python线程指南

    来自AstalWind的好文,彻底认识python线程 http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html . . . . .

  10. HDU 5868 Different Circle Permutation Burnside引理+矩阵快速幂+逆元

    题意:有N个座位,人可以选座位,但选的座位不能相邻,且旋转不同构的坐法有几种.如4个座位有3种做法.\( 1≤N≤1000000000 (10^9) \). 题解:首先考虑座位不相邻的选法问题,如果不 ...