MySQL 8.0+ 默认启用 ONLY_FULL_GROUP_BY 导致 GROUP BY 报错,因非聚合字段未出现在 GROUP BY 中;可临时会话级禁用、永久配置文件修改或重写 SQL 适配标准语义。

MySQL 8.0+ 默认启用 ONLY_FULL_GROUP_BY 导致 GROUP BY 报错
MySQL 5.7.5 起默认开启 ONLY_FULL_GROUP_BY 模式,升级到 8.0 后很多旧 SQL 突然报错:Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column...。这不是语法错了,是 MySQL 强制要求:SELECT 中所有非聚合字段必须出现在 GROUP BY 子句中。
临时绕过:用 SET 修改当前会话的 sql_mode
适合开发调试或迁移过渡期,不建议长期用于生产环境。执行以下语句可立即生效(仅对当前连接有效):
SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
验证是否生效:
SELECT @@sql_mode;
注意:SESSION 级修改重启连接即失效;若想对当前用户所有新会话生效,需改 GLOBAL 级,但需要 SUPER 权限,且可能影响其他应用。
永久禁用:修改 MySQL 配置文件 my.cnf 或 my.ini
适用于 Docker、云数据库自建实例等可控环境。找到配置文件,在 [mysqld] 段落下添加:
sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
关键点:
MySQL 数据库管理技能,能够通过自然语言查询和管理数据库,支持 SELECT/INSERT/UPDATE/DELETE、表管理、备份恢复等操作。当用户提及 MySQL、数据库查询、建表或数据备份时使用此技能。
- 必须显式列出你想要保留的模式项,不能只写
sql_mode = ""—— 空值会被 MySQL 自动补全为默认集,ONLY_FULL_GROUP_BY仍可能被加回 - 修改后需重启 MySQL 服务(
systemctl restart mysqld或service mysql restart) - 云数据库(如阿里云 RDS、腾讯云 CDB)通常不开放配置文件修改权限,只能通过控制台参数模板调整
sql_mode参数
更推荐的做法:重写 SQL,适配标准 GROUP BY 语义
直接关掉 ONLY_FULL_GROUP_BY 是“治标”,容易掩盖逻辑缺陷。比如下面这种常见写法:
SELECT id, name, MAX(score) FROM student GROUP BY class;
它本意是“每个班级取最高分学生”,但实际执行时 id 和 name 是随机选的(MySQL 5.7 前行为),结果不可靠。正确写法应是:
SELECT s1.* FROM student s1<br>WHERE s1.score = (<br> SELECT MAX(s2.score) FROM student s2 WHERE s2.class = s1.class<br>);
或者用窗口函数(MySQL 8.0+):
SELECT id, name, score, class FROM (<br> SELECT *, ROW_NUMBER() OVER (PARTITION BY class ORDER BY score DESC) rn<br> FROM student<br>) t WHERE rn = 1;
这类改写虽多几行,但语义清晰、结果确定,也避免未来因模式变更再次出问题。
真正麻烦的不是怎么关掉它,而是旧业务里大量隐式依赖非标准 GROUP BY 的逻辑——这些地方即使 SQL 跑通了,结果也可能早已不对,只是没人发现。










