GROUP BY 和 ORDER BY 不能直接组合实现“每组取最新/最高一条”,因 GROUP BY 先执行且只保留每组首行,ORDER BY 仅对其排序;正确方案是窗口函数或关联子查询。
GROUP BY 和 ORDER BY 不能随便连用,否则查出来的不是你想要的那条记录——尤其是想“每组取最新/最高的一条”时,几乎必然出错。
MySQL 5.7+ 默认开启 ONLY_FULL_GROUP_BY,只要 ORDER BY 后的字段没出现在 GROUP BY 子句中,也没被 MAX()、COUNT() 等包裹,就会直接报错:Expression #1 of ORDER BY clause is not in GROUP BY clause。
SELECT examId, score FROM ko_monthly_exam_history GROUP BY examId ORDER BY score DESC(score 既没分组也没聚合)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, score ORDER BY score DESC(但语义已变,不再是“每组一条”,而是去重组合)GROUP BY 先执行,只保留每组“第一行”(物理顺序或引擎默认行为),ORDER BY 对的是这“一行”的字段再排一次序,跟组内其他数据完全无关。
SELECT id, examId, score FROM t GROUP BY examId ORDER BY score DESC 返回的 id 很可能对应的是该组低分记录,不是最高分那条FROM → WHERE → GROUP BY → SELECT → ORDER BY,ORDER BY 根本看不到组内全量数据ORDER BY 再 GROUP BY”:MySQL 5.7+ 优化器会丢弃子查询里的 ORDER BY,除非加 LIMIT 999999999 强制保留(不推荐)想按 examId 分组,取每组 score 最高且 time 最新的那条完整记录,必须跳出 GROUP 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
SELECT t1.* FROM ko_monthly_exam_history t1 WHERE t1.id = (SELECT id FROM ko_monthly_exam_history t2 WHERE t2.examId = t1.examId ORDER BY score DESC, time DESC LIMIT 1)
LIMIT 的坑:SELECT * FROM (SELECT * FROM t ORDER BY score DESC LIMIT 1000) s GROUP BY examId 可能漏掉没进前 1000 的 examId,LIMIT 必须放最外层即使语法合法、逻辑正确,如果 ORDER BY 字段没索引,MySQL 会走 Using filesort,结果顺序看似随机,性能也差。
EXPLAIN 看 Extra 列:出现 Using filesort 就说明没走索引排序ORDER BY 字段尽量落在驱动表(FROM 后第一张表)上examId 分组、再按 MAX(time) 排序,建 INDEX idx_exam_time (examId, time)
ORDER BY 2 这类位置引用——字段一增减就全乱最容易被忽略的点是:你以为 GROUP BY + ORDER BY 能取每组最优记录,其实它只负责把组排个序;真正筛选组内数据,得靠窗口函数、子查询或业务层二次处理。别让 ONLY_FULL_GROUP_BY 报错把你骗过去——报错只是表象,逻辑错才是根因。