MySQL 5.7+ 默认启用 ONLY_FULL_GROUP_BY,导致非聚合字段未出现在 GROUP BY 中时报错1055;可通过 SELECT @@GLOBAL.sql_mode 检查是否启用,临时用 SET SESSION 修改,永久需调整配置文件或重写 SQL 使用 ANY_VALUE() 或补全 GROUP BY。

MySQL 5.7+ 默认启用 ONLY_FULL_GROUP_BY,只要 SELECT 列里有非聚合字段、又没出现在 GROUP BY 子句中,就会报错 ERROR 1055。这不是 bug,是 MySQL 主动收紧语义以避免歧义结果——直接改 sql_mode 是最快解法,但得清楚代价。
怎么看当前 sql_mode 是否启用了 ONLY_FULL_GROUP_BY
连上 MySQL 后执行:
SELECT @@GLOBAL.sql_mode;
如果返回值里包含 ONLY_FULL_GROUP_BY(通常在最前面),就确认触发了该限制。注意:@@SESSION.sql_mode 可能和全局不同,临时会话级修改只影响当前连接。
- 云数据库(如阿里云 RDS、腾讯云 CDB):进控制台「参数设置」,搜
sql_mode,去掉ONLY_FULL_GROUP_BY勾选,重启实例生效 - 本地或自建 MySQL:查完后别急着改,先复制完整字符串,再删掉
ONLY_FULL_GROUP_BY和多余的逗号
临时关闭 ONLY_FULL_GROUP_BY(当前会话有效)
适合调试、测试或 CI/CD 环境中快速验证 SQL 是否能跑通,不影响其他连接:
SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY,', ''));
⚠️ 注意:REPLACE 不会处理开头或结尾的逗号,更稳妥的是显式赋值:
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
- 执行后立即生效,但断开重连就恢复原状
- MySQL 8.0+ 已移除
NO_AUTO_CREATE_USER,若原配置含此项,必须删掉,否则SET会报ERROR 1231 - 应用代码里硬编码
SET SESSION是反模式,仅限临时排查
永久关闭(需重启 MySQL)
编辑 MySQL 配置文件(Linux 是 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf;Windows 是 my.ini),在 [mysqld] 段落下添加:
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
✅ 必须写在 [mysqld] 下,写在 [client] 或文件末尾无效;
- 改完保存,执行
sudo systemctl restart mysql(或对应服务名) - 重启后务必再执行
SELECT @@GLOBAL.sql_mode;确认ONLY_FULL_GROUP_BY真的消失了 - 某些 Docker 镜像或云数据库不支持直接改配置文件,只能走控制台参数管理
为什么推荐优先修 SQL 而不是关模式
关掉 ONLY_FULL_GROUP_BY 后,下面这种 SQL 能跑通,但结果不可靠:
SELECT user_id, name, COUNT(*) FROM orders GROUP BY user_id;
其中 name 字段没参与分组也没聚合,MySQL 会随机选某一行的 name 返回,下次执行可能不一样。
- 正确做法是明确语义:用
MAX(name)、ANY_VALUE(name)(MySQL 5.7+),或把name加进GROUP BY - 如果业务上
user_id和name是 1:1 关系,加name到GROUP BY最安全;如果是多对一,必须用聚合函数表达意图 - 很多 ORM 自动生成的 SQL(如 Django 的
.values()+.annotate())在 MySQL 5.7+ 上会突然崩,根源常是没对齐分组字段,此时修 SQL 比改库配置更治本
真正难的不是怎么关,而是关了之后,那些原本“侥幸”跑通的 SQL,到底返回的是哪个值——没人能保证。











