MySQL5与MySQL8聚合函数SELECT语句结果差异原因及兼容咨询
MySQL 5与8聚合函数+左连接结果差异分析及兼容方案
差异原因
你的SQL里用了LEFT JOIN但在WHERE子句里加了B.del_flg = 0,这直接改变了左连接的逻辑:
- 左连接原本会保留A表中所有符合
A.student_id = 1的行,B表无匹配时对应列值为NULL。但WHERE B.del_flg = 0会过滤掉B表列为NULL的行(因为NULL = 0不成立)。 - MySQL 5默认未开启
ONLY_FULL_GROUP_BY模式,当查询包含聚合函数(如MAX())但未显式分组时,会做非标准的宽松处理:即使连接后的结果被WHERE过滤得没有有效B行,依然保留A表中匹配行的非聚合列值,同时MAX(B.number)因无有效数据返回NULL。 - MySQL 8默认开启了
ONLY_FULL_GROUP_BY,严格遵循SQL标准:当聚合函数作用于空数据集时,不仅聚合结果为NULL,未被分组的非聚合列(A.student_id、A.school_id)也没有合法取值,因此返回全NULL的行。
MySQL 5的行为是否属于Bug?
不算严格意义的Bug,是MySQL 5为兼容旧业务做的非标准妥协。这种模式下允许SELECT列表出现不在GROUP BY中的非聚合列,MySQL会随机选取该列的一个值(这里刚好A表只有一行匹配,所以取到了预期值),但不符合SQL标准规范,复杂场景下可能返回不可预期的结果。
MySQL 8下保持结果一致的方案
把B表的过滤条件从WHERE移到LEFT JOIN的ON子句中,这样只会过滤参与左连接的B表数据,不会丢弃A表的匹配行:
SELECT A.student_id, A.school_id, max(B.number) AS max_number FROM A LEFT JOIN B ON B.student_id = A.student_id AND B.del_flg = 0 -- 将B表过滤条件移至此处 WHERE A.student_id = 1
调整后,MySQL 8会保留A表student_id=1的行,B表无匹配时MAX(B.number)返回NULL,和MySQL 5的结果完全一致。
内容的提问来源于stack exchange,提问作者上西潤
相关产品推荐
相关产品推荐

