SQL分组查询报错:如何获取各课程中学生首次出现的记录?
解决每个课程中学生首次出现记录的查询问题
首先,你原来的查询报错是因为GROUP BY Course时,SELECT子句里的StudentName、Studentmailid、Score既没有包含在GROUP BY分组字段中,也没有使用聚合函数(比如MAX()、MIN()),这不符合SQL的标准规范,数据库无法确定要返回这些字段的哪一个值,所以会抛出错误。
你的需求是获取每个课程+学生组合的首次出现记录(比如Student1在Course A的第一条记录,Student2在Course A的第一条,Student1在Course B的第一条),下面提供几种通用的解决方案,适用于不同的数据库环境:
方法一:使用窗口函数(推荐,适用于MySQL 8+、PostgreSQL、SQL Server等)
窗口函数ROW_NUMBER()可以轻松实现分组取第一条记录的需求。我们先按Course和StudentName分组,给每个组内的记录按插入顺序(假设你有一个自增主键id,用来判断记录的先后顺序)编号,然后筛选出编号为1的记录:
SELECT StudentName, Course, Studentmailid, Score FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY Course, StudentName ORDER BY id -- 这里的id是表中自增主键,用来确定记录的先后顺序 ) AS row_num FROM StudentTable ) AS temp_table WHERE row_num = 1;
如果你的表没有自增主键,也可以用其他能确定记录顺序的字段(比如创建时间create_time)替换id。如果实在没有这类字段,虽然不推荐,但可以尝试用Score或其他字段排序,但结果可能和预期有偏差。
方法二:使用关联子查询(适用于MySQL 5.x等不支持窗口函数的版本)
如果你的数据库不支持窗口函数,可以通过子查询先找出每个Course+StudentName组合的最早记录的标识(比如最小的id),再关联原表获取完整数据:
SELECT s.StudentName, s.Course, s.Studentmailid, s.Score FROM StudentTable s INNER JOIN ( SELECT Course, StudentName, MIN(id) AS earliest_id FROM StudentTable GROUP BY Course, StudentName ) AS grouped_s ON s.id = grouped_s.earliest_id;
验证结果
针对你的测试数据,执行以上任意一种查询,都会返回你想要的记录:
- Student1 | A | student1@gmail.com | 80
- Student2 | A | student2@gmail.com | 70
- Student1 | B | student2@gmail.com | 70
完全符合你预期的记录1、3、4。
内容的提问来源于stack exchange,提问作者user13597631
相关产品推荐
相关产品推荐

