SQL技术问询:如何用GROUP BY和HAVING筛选低于平均最低分的测验
问题分析与解决方案
你的SQL语句返回空结果的核心原因是分组逻辑错误,导致HAVING子句里的平均值计算范围完全不对:
- 你把
lowscore加入了GROUP BY列表,这会让每个分组只包含单个lowscore值。此时avg(lowscore)计算的是当前分组内的平均值(也就是这个lowscore本身),自然lowscore < avg(lowscore)永远不成立,所以没有数据返回。 - 你手动输入14能得到正确结果,是因为14是所有测验lowscore的全局平均值,而不是分组内的平均值。
下面是两种符合你要求(使用GROUP BY和HAVING)的正确写法:
方案一:子查询获取全局平均分
先通过子查询计算所有测验最低分的平均值,再在HAVING中比较当前测验的最低分是否低于这个全局值:
SELECT quiznum, quizdate FROM quizzes GROUP BY quiznum, quizdate HAVING lowscore < (SELECT AVG(lowscore) FROM quizzes);
注:如果你的
quizzes表中,同一个quiznum+quizdate对应多条记录(比如记录了该测验所有学生的成绩,lowscore是单条记录的分数),那你需要先聚合得到每个测验的最低分,再做比较:WITH quiz_low_scores AS ( SELECT quiznum, quizdate, MIN(lowscore) AS quiz_low FROM quizzes GROUP BY quiznum, quizdate ) SELECT quiznum, quizdate FROM quiz_low_scores GROUP BY quiznum, quizdate HAVING quiz_low < (SELECT AVG(quiz_low) FROM quiz_low_scores);
方案二:窗口函数(适用于支持SQL:2003及以上的数据库)
用窗口函数直接计算全局平均分,再筛选符合条件的测验:
SELECT DISTINCT quiznum, quizdate FROM ( SELECT quiznum, quizdate, lowscore, AVG(lowscore) OVER () AS global_avg_low FROM quizzes ) AS sub_query WHERE lowscore < global_avg_low;
这个方法不需要嵌套多层子查询,可读性更强,适合MySQL 8.0+、PostgreSQL、SQL Server等现代数据库。
内容的提问来源于stack exchange,提问作者progowl
相关产品推荐
相关产品推荐

