数据库记录
mysql> select * from score_info;
+----+--------+----------+-------+
| id | name | class_no | score |
+----+--------+----------+-------+
| 1 | 张三 | 高三1班 | 90 |
| 2 | 李四 | 高三1班 | 92 |
| 3 | 王五 | 高三1班 | 99 |
| 4 | 赵流 | 高三1班 | 93 |
| 5 | 孙启 | 高三1班 | 95 |
| 6 | 古蔺 | 高三2班 | 93 |
| 7 | 孙雪 | 高三2班 | 92 |
| 8 | 万凯 | 高三2班 | 88 |
| 9 | 李润 | 高三2班 | 98 |
| 10 | 林旭 | 高三2班 | 100 |
| 11 | 艾奇 | 高三2班 | 98 |
| 12 | 爱丽斯 | 高三3班 | 97 |
| 13 | 詹姆斯 | 高三3班 | 93 |
| 14 | 阿伦 | 高三3班 | 91 |
| 15 | 史提芬 | 高三3班 | 99 |
| 16 | 克里斯 | 高三3班 | 97 |
+----+--------+----------+-------+
分组 TopN 问题
实现每个班级成绩前两名的学生信息
-- 实现方式_1
SELECT *
FROM score_info si
WHERE (
SELECT COUNT(1)
FROM score_info
WHERE class_no = si.class_no AND score > si.score
) < 2
ORDER BY si.class_no, si.score DESC;
-- 实现方式_2
SELECT *
FROM score_info si
WHERE EXISTS (
SELECT 1
FROM score_info
WHERE class_no = si.class_no AND score > si.score
HAVING COUNT(1) < 2
)
ORDER BY si.class_no, si.score DESC;
-- 实现方式_3
SELECT si.*
from score_info si
LEFT JOIN score_info sii ON sii.class_no = si.class_no AND si.score < sii.score
GROUP BY si.id, si.`name`, si.class_no, si.score
HAVING COUNT(sii.id) < 2
ORDER BY si.class_no, si.score DESC;
+----+--------+----------+-------+
| id | name | class_no | score |
+----+--------+----------+-------+
| 3 | 王五 | 高三1班 | 99 |
| 5 | 孙启 | 高三1班 | 95 |
| 10 | 林旭 | 高三2班 | 100 |
| 9 | 李润 | 高三2班 | 98 |
| 11 | 艾奇 | 高三2班 | 98 |
| 15 | 史提芬 | 高三3班 | 99 |
| 12 | 爱丽斯 | 高三3班 | 97 |
| 16 | 克里斯 | 高三3班 | 97 |
+----+--------+----------+-------+
不用limit实现的原因
: 用 limit 实现的话, 如果有分数并列的情况的话会遗漏数据
建表语句
CREATE TABLE `score_info` (
`id` bigint(18) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`class_no` varchar(10) DEFAULT NULL,
`score` int(5) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;