GROUP BY后ORDER BY必须作用于GROUP BY列或聚合结果,否则报错或结果不可靠;执行顺序为GROUP BY→聚合→ORDER BY,无法直接通过ORDER BY获取每组最新/最高记录,须用窗口函数或子查询实现。

GROUP BY 和 ORDER BY 不能随便连用,否则查出来的不是你想要的那条记录。
ORDER BY 字段必须出现在 GROUP BY 或聚合函数中
MySQL(尤其是 5.7 严格模式或 8.0+)会直接报错:Expression #1 of ORDER BY clause is not in GROUP BY clause。这是因为 GROUP BY 后每组只保留一行,而 ORDER BY 想排序的字段如果既没参与分组、又没套聚合函数,数据库不知道该拿哪条值来排。
- ✅ 正确写法:
SELECT examId, MAX(score) AS score FROM ko_monthly_exam_history GROUP BY examId ORDER BY score DESC - ❌ 错误写法:
SELECT examId, score FROM ko_monthly_exam_history GROUP BY examId ORDER BY score DESC(score未聚合也未分组) - 注意:即使开了
sql_mode宽松模式(如去掉ONLY_FULL_GROUP_BY),结果也是不可靠的——MySQL 会随机选组内某行的score值来排序,不是最大值也不是最新时间
GROUP BY 先执行,ORDER BY 对的是“分组后那一行”,不是原始数据
很多人以为 GROUP BY ... ORDER BY time DESC 能拿到每组里最新的那条记录,其实不能。分组时 MySQL 默认取“第一行”(物理存储顺序),ORDER BY 只是对这“第一行”的字段再排一次序,跟组内其他行无关。
- 现象举例:按
examId分组想取最高分记录,但SELECT id, examId, score FROM t GROUP BY examId ORDER BY score DESC返回的id很可能对应的是低分那条 - 根本原因:执行顺序是
FROM → WHERE → GROUP BY → SELECT → ORDER BY,ORDER BY看不到组内全量数据 - 真正要取每组最新/最高记录,得用子查询或窗口函数,比如:
SELECT * FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY examId ORDER BY score DESC, time DESC) AS rn FROM ko_monthly_exam_history) t WHERE t.rn = 1
用子查询“先排序再分组”容易踩 LIMIT 的坑
有人试过先 ORDER BY score DESC 再 GROUP BY,看起来能拿到高分记录,但加了 LIMIT 就危险——LIMIT 在子查询里生效,会先截断再分组,导致某些 examId 根本没被扫到。
- 错误示范:
SELECT * FROM (SELECT * FROM ko_monthly_exam_history ORDER BY score DESC LIMIT 1000) t GROUP BY examId(可能漏掉低分但重要的组) - 正确思路:分组逻辑必须覆盖全部目标数据,
LIMIT应该放在最外层,或者用ROW_NUMBER()+WHERE rn = 1控制每组只取一条 - 性能提醒:
GROUP_CONCAT(... ORDER BY ...)+SUBSTRING_INDEX方案在大数据量下会变慢,且group_concat_max_len有默认限制(1024),超长会被截断
聚合函数和非聚合字段混用时,字段语义容易混淆
MAX(score) 是明确的,但 id、time、state 这些字段如果没加聚合,MySQL 不保证它们和 MAX(score) 来自同一行——这是最容易被忽略的实际后果。
- 比如:
SELECT examId, MAX(score), id, time FROM t GROUP BY examId,id和time可能来自任意一条同examId的记录,不一定是分数最高的那条 - 安全做法:要么全部用聚合函数包裹(
MAX(time)、MIN(id)),要么用窗口函数确保字段对齐 - 如果你依赖
id去关联其他表,这种“错配”会导致 JOIN 结果异常,线上出过不少隐蔽 bug
真正难的不是语法,而是意识到:GROUP BY 不是“挑一条”,而是“坍缩一组”。想挑特定的一条,就得显式定义规则——靠 ORDER BY + GROUP BY 连用,永远做不到可靠。

















