(1)mysql--查询成绩最高和最低的人

本文介绍如何使用SQL查询成绩表中每门科目的最高分和最低分的学生姓名及分数。通过逐步分解,展示了如何结合使用GROUP BY、MAX和MIN函数来获取所需的数据。

简单描述:
成绩表中有学生姓名、学生科目以及学生分数。查询分数最高和分数最低的学生的以及学生的分数。注意的点如下:

1、group by,select 选择的列,必须是group by 中的列,或者是函数形式。
2、利用MAX() 和MIN()sql函数。
3、建立的表结构如下。

-- ----------------------------
-- Table structure for grade
-- ----------------------------
DROP TABLE IF EXISTS `grade`;
CREATE TABLE `grade` (
  `stu_name` varchar(255) NOT NULL,
  `stu_subject` varchar(255) NOT NULL,
  `score` int(255) DEFAULT NULL,
  PRIMARY KEY (`stu_subject`,`stu_name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- ----------------------------
-- Records of grade
-- ----------------------------
INSERT INTO `grade` VALUES ('lilei', 'shuxue', '99');
INSERT INTO `grade` VALUES ('xiaoyong', 'shuxue', '66');
INSERT INTO `grade` VALUES ('lilei', 'yingyu', '80');
INSERT INTO `grade` VALUES ('xiaoyong', 'yingyu', '55');
INSERT INTO `grade` VALUES ('lilei', 'yuwen', '78');
INSERT INTO `grade` VALUES ('xiaoyong', 'yuwen', '88');

思路
1)按照科目分组查询成绩最高的人
SELECT grade.stu_subject, MAX(grade.score) as score from grade GROUP BY stu_subject;
2)显示出成绩最高的人的姓名和科目名称
SELECT grade.* from grade,
(SELECT grade.stu_subject, MAX(grade.score) as score from grade GROUP BY stu_subject )b
WHERE grade.score = b.score and grade.stu_subject = b.stu_subject;
3)显示出列标题.
SELECT “成绩最高”,grade.* from grade,
(SELECT grade.stu_subject, MAX(grade.score) as score from grade GROUP BY stu_subject )b
WHERE grade.score = b.score and grade.stu_subject = b.stu_subject;

成绩最低的也是如此就是利用MIN()函数, 如果需要同时查出, 可以用union 如下sql

SELECT "成绩最高",grade.* from grade, 
(SELECT  grade.stu_subject, MAX(grade.score) as score  from grade GROUP BY  stu_subject  )b
WHERE grade.score = b.score and grade.stu_subject = b.stu_subject
UNION
SELECT "成绩最低",grade.* from grade, 
(SELECT  grade.stu_subject, MIN(grade.score) as score  from grade GROUP BY  stu_subject  )b
WHERE grade.score = b.score and grade.stu_subject = b.stu_subject;

查询结果如下图所示:
这里写图片描述

总结:
路漫漫其修远兮,吾将上下而求索。

<think> 我们参考用户提供的引用内容,特别是引用[1]引用[3]中的方法,来解决查询每个班级总成绩最高的问题。 注意:用户要求的是总成绩最高,但原表结构(如引用[1]中的表)是每门课的成绩记录,因此我们需要先计算每个学生的总成绩,然后再按班级分组找出每个班级总成绩最高的学生。 步骤: 1. 计算每个学生的总成绩(需要先按学生分组求)。 2. 按班级分组,找出每个班级的最高成绩。 3. 将步骤1的结果与步骤2的结果连接,找出每个班级中总成绩等于该班级最高成绩的学生。 然而,引用[1]中的表结构是每行代表一个学生的各科成绩?实际上,引用[1]中的表结构是: CREATE TABLE `t_student` ( `id` int(11) NOT NULL, `class` varchar(45) DEFAULT NULL, `name` varchar(45) DEFAULT NULL, `score` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) 这个表结构看起来是每个学生的成绩记录,但是注意,如果每个学生有多门课,那么同一个学生会有多条记录(不同的科目)。因此我们需要先按学生分组求得到总成绩。 但是,观察引用[1]中的查询,他们直接对score进行max,并且按class分组。这实际上是不正确的,因为这里没有考虑每个学生有多门课的情况。所以我们需要先计算每个学生的总成绩。 因此,我们需要先创建一个视图(或使用子查询)来计算每个学生的总成绩,然后再进行分组查询。 参考引用[1]中的第二种写法(使用子查询)并加以改进。 假设我们的表结构如下(如引用[1]): t_student: id, class, name, score 注意:这里的score是某门课的成绩,一个学生有多条记录(多门课程)。因此,我们需要先计算每个学生的总成绩。 步骤: 1. 计算每个学生的总成绩(按学生id分组,求score)。 2. 然后按班级分组,找出每个班级的最高成绩。 3. 再找出每个班级中总成绩等于该班级最高成绩的学生。 但是,注意同一个班级可能有多个学生总成绩相同且都是最高分,所以我们要考虑并列的情况。 因此,我们可以这样写: 方法1:使用子查询(类似于引用[1]中的第二种写法,但需要先计算总成绩) 步骤1:先计算每个学生的总成绩(作为一个子查询) 步骤2:计算每个班级的最高成绩(按班级分组) 步骤3:将步骤1的结果与步骤2的结果连接,条件为班级相同且总成绩等于该班级的最高成绩。 具体SQL语句如下: ```sql -- 步骤1:计算每个学生的总成绩 WITH student_total AS ( SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name -- 注意:这里按班级姓名分组,但同一个班级可能有同名?所以最好用学生ID -- 但是原表中没有学生ID?注意原表有id字段,但它是主键,每个学生每门课一条记录,所以同一个学生的记录id不同,但name相同?这样分组会有问题。 -- 因此,我们需要按学生id来分组,但原表结构中没有学生唯一标识?注意原表有id,但是它是主键,每门课一个记录,所以同一个学生会有多个id(不同记录)? -- 这实际上是一个设计问题。但是,根据引用[1]的表结构,我们无法区分同一个学生的不同课程记录?因为同一个学生的多条记录只有id不同,但nameclass相同?所以我们需要按nameclass分组。 -- 但这样会有问题:同一个班级可能有同名的。所以正确的表设计应该有一个学生ID(学号)来唯一标识学生,并且每门课的成绩记录关联该学号。 -- 然而,根据引用[1]的表结构,我们只能暂时假设同一个班级内同一个姓名代表同一个学生(因为用户没有提供更多信息)。所以按classname分组。 -- 但是,用户提供的原始表结构是:`t_student` (id, class, name, score),其中id是主键。这意味着每条记录代表一个学生的某一门课成绩?那么同一个学生会有多条记录,但每条记录的id不同,class相同(同一个班),name相同。 -- 因此,我们按classname分组求,得到每个学生的总成绩) -- 但是,由于可能存在同名问题,我们可能需要使用原表中的id来标识学生?但是原表没有学生唯一标识(同一个学生不同课程记录id不同)。所以这里我们只能认为同一个班级同一个姓名的学生是同一个-- 步骤23: SELECT t1.class, t1.name, t1.total_score FROM student_total t1 INNER JOIN ( SELECT class, MAX(total_score) AS max_total_score FROM student_total GROUP BY class ) t2 ON t1.class = t2.class AND t1.total_score = t2.max_total_score; -- 但是,如果同名问题存在,这个方法就不准确。为了解决这个问题,我们必须在原始表中有一个学生唯一标识(例如学号)。假设没有,我们只能这样做。 -- 另一种写法(不使用CTE,使用子查询嵌套): SELECT t1.class, t1.name, t1.total_score FROM (SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name ) t1 WHERE (t1.class, t1.total_score) IN ( SELECT class, MAX(total_score) FROM ( SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name ) t2 GROUP BY class ); -- 或者更简洁的写法(但MySQL支持在IN子句中使用元组): SELECT t1.class, t1.name, t1.total_score FROM (SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name ) t1 WHERE (t1.class, t1.total_score) IN ( SELECT class, MAX(total_score) FROM ( SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name ) t2 GROUP BY class ); ``` 但是,这种方法需要嵌套两层子查询,性能可能较差。我们也可以使用窗口函数(如果MySQL版本支持的话,MySQL 8.0+)来优化。 方法2:使用窗口函数(ROW_NUMBER或RANK) 步骤: 1. 先计算每个学生的总成绩。 2. 按班级分区,按总成绩降序排序,给每个学生排名。 3. 取出每个班级的第一名(注意并列情况,使用RANK或DENSE_RANK) 但是,如果使用RANK,并列第一的学生都会排在第一,然后第二名就是第三名(如果有两个第一)。所以我们用RANK=1SQL语句: ```sql WITH student_total AS ( SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name ), ranking AS ( SELECT class, name, total_score, RANK() OVER (PARTITION BY class ORDER BY total_score DESC) AS rank_num FROM student_total ) SELECT class, name, total_score FROM ranking WHERE rank_num = 1; ``` 注意:这里使用RANK(),如果总成绩相同,则并列第一,都会显示出来。 但是,用户提供的引用[2]中提到了前三名(包括并列)的写法,使用的是EXISTS子查询,但那个方法相对复杂,我们可以用窗口函数更简洁。 如果数据库不支持窗口函数(如MySQL 5.7),我们可以使用方法1或者引用[1]中的连接方法。 方法3:使用连接(类似于引用[1]中的第一种方法,但先计算总成绩) ```sql -- 先计算每个学生的总成绩(临时表) CREATE TEMPORARY TABLE temp_student_total AS SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name; -- 然后,连接每个班级的最高成绩 SELECT t1.class, t1.name, t1.total_score FROM temp_student_total t1 INNER JOIN ( SELECT class, MAX(total_score) AS max_total_score FROM temp_student_total GROUP BY class ) t2 ON t1.class = t2.class AND t1.total_score = t2.max_total_score; -- 或者不用临时表,直接子查询: SELECT t1.class, t1.name, t1.total_score FROM (SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name) t1 INNER JOIN (SELECT class, MAX(total_score) AS max_total_score FROM (SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name) t GROUP BY class) t2 ON t1.class = t2.class AND t1.total_score = t2.max_total_score; ``` 总结:推荐使用窗口函数(如果MySQL版本>=8.0)或者使用第一种方法(连接或IN子查询)。 考虑到用户提供的引用[1]中的表结构,我们假设同一个班级同名就是同一个学生(否则需要用户提供学生唯一标识)。如果表中有学生唯一标识(如学号),则应该按学号分组,这样更准确。 例如,如果表中有student_id(学生唯一标识),那么我们应该这样写: ```sql WITH student_total AS ( SELECT class, student_id, ANY_VALUE(name) AS name, -- 或者直接选择name,因为同一个student_id的name应该相同 SUM(score) AS total_score FROM t_student GROUP BY class, student_id ), ranking AS ( SELECT class, student_id, name, total_score, RANK() OVER (PARTITION BY class ORDER BY total_score DESC) AS rank_num FROM student_total ) SELECT class, student_id, name, total_score FROM ranking WHERE rank_num = 1; ``` 由于用户没有提到学生唯一标识,所以我们按照引用[1]的表结构(只有id, class, name, score)来处理。注意:id是主键,每门课一条记录,但同一个学生没有唯一标识,所以只能按classname分组。 因此,最终我们给出两种方法(考虑同名问题,但无法避免,除非表结构有唯一学生标识): 方法一(使用窗口函数,MySQL 8.0+): ```sql WITH student_total AS ( SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name ), ranking AS ( SELECT class, name, total_score, RANK() OVER (PARTITION BY class ORDER BY total_score DESC) AS rank_num FROM student_total ) SELECT class, name, total_score FROM ranking WHERE rank_num = 1; ``` 方法二(使用连接,兼容MySQL 5.x): ```sql SELECT t1.class, t1.name, t1.total_score FROM (SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name ) t1 INNER JOIN ( SELECT class, MAX(total_score) AS max_total_score FROM ( SELECT class, name, SUM(score) AS total_score FROM t_student GROUP BY class, name ) t_inner GROUP BY class ) t2 ON t1.class = t2.class AND t1.total_score = t2.max_total_score; ``` 注意:在实际应用中,如果数据量较大,临时表可能影响性能,可以考虑创建适当的索引或物化视图。 根据用户提供的引用,我们使用了引用[1]中的连接思想引用[2]中的排名思想。 最后,我们生成相关问题: </think> ### 查询每个班级总成绩最高学生的方法 基于引用内容[^1][^3],以下是三种可靠方法(考虑并列情况): #### 方法1:使用子查询连接(兼容性好) ```sql SELECT s.class, s.id, s.name, s_total.total_score FROM ( SELECT class, id, name, SUM(score) AS total_score FROM t_student GROUP BY class, id -- 按班级学生分组计算总分 ) s_total JOIN ( SELECT class, MAX(total_score) AS max_score FROM ( SELECT class, id, SUM(score) AS total_score FROM t_student GROUP BY class, id ) t GROUP BY class -- 获取每个班级最高总分 ) max_scores ON s_total.class = max_scores.class AND s_total.total_score = max_scores.max_score ORDER BY s_total.class; ``` #### 方法2:WHERE IN子查询(简洁写法) ```sql SELECT class, id, name, SUM(score) AS total_score FROM t_student GROUP BY class, id HAVING (class, SUM(score)) IN ( SELECT class, MAX(total_score) FROM ( SELECT class, id, SUM(score) AS total_score FROM t_student GROUP BY class, id ) t GROUP BY class -- 过滤出最高分组合 ); ``` #### 方法3:窗口函数(MySQL 8.0+ 高效方案) ```sql WITH student_scores AS ( SELECT class, id, name, SUM(score) AS total_score, RANK() OVER (PARTITION BY class ORDER BY SUM(score) DESC) AS rank_num FROM t_student GROUP BY class, id ) SELECT class, id, name, total_score FROM student_scores WHERE rank_num = 1; -- 取每个班级排名第一的学生 ``` ### 关键说明: 1. **分组逻辑** - 先按 `(class, id)` 分组计算每个学生的总分(避免同名问题) - 再按 `class` 分组找最高分[^1][^3] 2. **并列处理** 所有方法都自动包含总分并列第一的学生,例如: ```mermaid graph LR A[班级A] --> B[张三 285分] A --> C[李四 285分] D[班级B] --> E[王五 292分] ``` 3. **性能建议** - 超过10万行数据优先使用方法3(窗口函数) - 在 `(class, id)` `score` 字段建索引加速聚合[^2] > **提示**:如果表中已有总成绩字段,可简化为 `WHERE (class, total_score) IN (SELECT class, MAX(total_score) FROM t_student GROUP BY class)`[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值