You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL中HAVING子句如何筛选行?分组查各班最高分结果异常

关于MySQL中HAVING子句筛选逻辑及查询异常的问题

场景与问题描述

现有存储学生成绩的sc表,表创建语句如下:

create table sc
(
    `classid` int,
    `studentid` int,
    `score` int
);

样本数据:

+---------+-----------+-------+
| classid | studentid | score |
+---------+-----------+-------+
|       1 |         1 |    50 |
|       1 |         2 |    59 |
|       1 |         3 |    80 |
|       1 |         4 |    68 |
|       1 |         5 |    70 |
|       1 |         6 |    20 |
|       1 |         7 |    90 |
|       1 |         8 |   100 |
|       1 |         9 |    25 |
|       2 |         1 |    51 |
|       2 |         2 |    59 |
|       2 |         3 |    80 |
|       2 |         4 |    68 |
|       2 |         5 |    70 |
|       2 |         6 |    30 |
|       2 |         7 |    44 |
|       2 |         8 |    80 |
|       3 |         1 |    20 |
|       1 |        11 |    30 |
|       1 |        12 |    40 |
+---------+-----------+-------+

想要查询每个班级的最高分,编写了如下SQL语句:

select * 
from sc 
group by classid 
having score = max(score);

但输出结果不符合预期,仅返回一行数据:

+---------+-----------+-------+
| classid | studentid | score |
+---------+-----------+-------+
|       3 |         1 |    20 |
+---------+-----------+-------+

请问MySQL中HAVING子句是如何筛选行的,为何查询结果异常?


解答

1. MySQL中HAVING子句的筛选逻辑

HAVING子句的作用是对GROUP BY分组后的结果集进行筛选,它仅能使用分组字段、聚合函数,或者被GROUP BY包含的字段(MySQL非严格模式下允许使用非分组字段,但这不符合SQL标准)。

注意:HAVING在分组完成后执行,而WHERE是在分组前过滤行。

2. 原SQL结果异常的原因

你的SQL存在两个核心问题:

  • 非分组字段直接出现在SELECT和HAVING中:用GROUP BY classid分组后,studentid和score都不属于分组字段。MySQL默认非严格模式下不会报错,但会返回分组中随机一行数据的studentid和score值,而非该组所有行。
  • HAVING条件逻辑错误:score = max(score)中,左边的score是分组后随机取出的某一行分数,右边的max(score)是该组最高分。只有当随机取出的行刚好是该组最高分的时候,才会被筛选出来。班级3只有一行数据,所以随机取的就是最高分,因此被返回;而班级1、2随机取的行不是最高分,所以被过滤掉了。

3. 正确的查询写法

要获取每个班级的最高分及对应学生信息,有几种常见写法:

写法一:子查询关联原表

SELECT sc.*
FROM sc
JOIN (
    SELECT classid, MAX(score) AS max_score
    FROM sc
    GROUP BY classid
) AS class_max ON sc.classid = class_max.classid AND sc.score = class_max.max_score;

写法二:窗口函数(MySQL 8.0+支持)

SELECT classid, studentid, score
FROM (
    SELECT *,
           RANK() OVER (PARTITION BY classid ORDER BY score DESC) AS rnk
    FROM sc
) AS ranked
WHERE rnk = 1;

这种写法可处理同班级多个最高分的情况(比如班级2有两个80分,都会被返回)。


内容的提问来源于stack exchange,提问作者JASON CHAN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 08:06:22