报错直接原因是字段未进group by或未套聚合函数;mysql 5.7.5+默认启用only_full_group_by模式,强制要求select中每个非聚合字段必须显式出现在group by子句中或被min/max/count/any_value等包裹,否则因语义不确定而拒绝执行。

报错直接原因是字段没进 GROUP BY 或没套聚合函数
MySQL 5.7.5+ 默认启用 ONLY_FULL_GROUP_BY,它强制要求:SELECT 列表里的每个非聚合字段,必须显式出现在 GROUP BY 子句中,或被 MIN()、MAX()、COUNT()、ANY_VALUE() 等包裹。否则就抛出错误:ERROR 1055 (42000),提示类似 “Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'db.table.col'”。这不是语法错误,是语义校验失败——MySQL 拒绝返回不确定的结果。
为什么旧 SQL 在 5.6 能跑,5.7 就挂了
MySQL 5.6 及更早版本默认不启用 ONLY_FULL_GROUP_BY,允许你写 SELECT id, name FROM user GROUP BY gender 这类语句。但此时 id 和 name 实际取的是分组内“某一行”的值,哪一行?由执行计划决定,不可预测。5.7 引入该模式,本质是堵住这个语义漏洞,向 SQL92 标准靠拢。所以升级后大量旧代码崩掉,不是 MySQL 变坏了,而是它终于开始说真话了。
查和改 sql_mode 的关键操作
别猜,先确认是不是它在作祟:
- 查当前会话模式:
SELECT @@session.sql_mode;(注意是@@session,不是@@global) - 如果返回值含
ONLY_FULL_GROUP_BY,就是它 - 临时禁用(仅当前连接):
SET SESSION sql_mode = REPLACE(@@session.sql_mode, 'ONLY_FULL_GROUP_BY,', ''); - 永久禁用(需重启):修改
my.cnf的[mysqld]段,重设sql_mode值,去掉ONLY_FULL_GROUP_BY
⚠️ 注意:SET GLOBAL sql_mode=... 虽然能全局生效,但部分云数据库(如阿里云 RDS、腾讯云 CDB)禁止该操作,必须走控制台参数设置。
真正推荐的解法:用 ANY_VALUE() 或重写逻辑
禁用 ONLY_FULL_GROUP_BY 是权宜之计,容易掩盖数据歧义。更稳妥的做法是明确语义:
- 如果你确实只需要每组任一值,用
ANY_VALUE(col)显式声明意图,比如:SELECT ANY_VALUE(id), name FROM user GROUP BY gender - 如果你要取最新/最老记录,别依赖 GROUP BY“碰巧”,改用窗口函数(MySQL 8.0+)或子查询 + JOIN
- 如果只是去重,
SELECT DISTINCT比模糊的 GROUP BY 更准确
复杂点在于:很多 ORM 自动生成的 SQL(比如 Laravel 的 groupBy() 配合 select('id', 'name'))不会自动加 ANY_VALUE(),得手动干预或升级驱动。这点最容易被忽略——你以为改了配置就万事大吉,结果上线后某条边缘查询又因隐式依赖“随机行”而返回错数据。











