用一条SQL语句写成每个班级分数前三高的所有学生:
stu表:
-- ----------------------------
-- Table structure for stu
-- ----------------------------
DROP TABLE IF EXISTS `stu`;
CREATE TABLE `stu` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`sname` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`score` int(255) DEFAULT NULL,
`classid` int(11) DEFAULT NULL,
PRIMARY KEY (`sid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of stu
-- ----------------------------
INSERT INTO `stu` VALUES (1, 'Joe', 85, 1);
INSERT INTO `stu` VALUES (2, 'Henry', 80, 2);
INSERT INTO `stu` VALUES (3, 'Sam', 60, 2);
INSERT INTO `stu` VALUES (4, 'Max', 90, 1);
INSERT INTO `stu` VALUES (5, 'Janet', 69, 1);
INSERT INTO `stu` VALUES (6, 'Randy', 85, 1);
INSERT INTO `stu` VALUES (7, 'Will', 70, 1);
INSERT INTO `stu` VALUES (8, 'Chen', 85, 2);
SET FOREIGN_KEY_CHECKS = 1;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for class
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
`cid` int(255) NOT NULL AUTO_INCREMENT,
`cname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
PRIMARY KEY (`cid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of class
-- ----------------------------
INSERT INTO `class` VALUES (1, '1-101');
INSERT INTO `class` VALUES (2, '1-102');
SET FOREIGN_KEY_CHECKS = 1;
答案:
select * from stu s,class
where s.classid = class.cid
and score >=
(
select distinct s1.score from stu s1 where s1.classid = class.cid
order by s1.score desc limit 2,1
)
order by classid,score desc;
分析:
先查询前三高的分数(记得去重),然后降序排序(因为分数要从高到低),如果一个班级只有2个以内高的分数(不重复),那么limit会自动选择这2个或2个以内。有3个或者3个以上的高成绩(不重复),那么刚好以第3条记录为边界条件。
以边界条件(分数)查出来结果集后,使用classid(默认升序)和score进行排序。
另外在LeetCode上面有一个题跟这个非常相似,难度为困难
部门工资前三高的所有员工, 这上面有很多解法。
其中有一个解法比较容易理解:
SELECT e1.Salary
FROM Employee AS e1
WHERE 3 >
(SELECT count(DISTINCT e2.Salary)
FROM Employee AS e2
WHERE e1.Salary < e2.Salary AND e1.DepartmentId = e2.DepartmentId) ;
大意是Salary表进行自连,去重后如果比e1.Salary高的薪水小于3条(如果等于3条的话,是不需要进行比较的,因为如果高过我的有3个,说明我是第4个,一般满足前3位的count(DISTINCT e2.Salary)
结果是:0,1,2),那么e1.Salary本身就是满足前3名薪水这个条件的,就把本身这条记录留下来。
https://leetcode-cn.com/problems/department-top-three-salaries/solution/185-bu-men-gong-zi-qian-san-gao-de-yuan-gong-by-li/