最稳妥解法是修改sql,用any_value()显式声明非确定性字段;若报错含“sql_mode=only_full_group_by”且@@sql_mode返回结果含该模式,则确认为此问题。

直接改 SQL 是最稳妥的解法,禁用 ONLY_FULL_GROUP_BY 只能临时绕过,且会让结果不可控。
怎么看报错是不是 ONLY_FULL_GROUP_BY 导致的
别猜,先执行这条命令确认:
SELECT @@sql_mode;
如果返回结果里包含 ONLY_FULL_GROUP_BY(通常排第一位),且错误末尾带 this is incompatible with sql_mode=only_full_group_by,那就坐实了。注意:@@sql_mode 输出是英文逗号加空格分隔的字符串,比如 'ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES,' —— 空格不能忽略。
- 云数据库(如阿里云 RDS)通常限制
SET GLOBAL sql_mode权限,执行会直接报ERROR 1227 - 本地或自建 MySQL 才能改全局配置,且必须重启服务才生效
优先改 SQL:用 ANY_VALUE() 显式表达意图
ANY_VALUE() 不是随机取值,而是向 MySQL 声明:“我接受这个字段在组内不唯一,结果不确定性由我承担”。它比关模式更可控,也比硬塞进 GROUP BY 更轻量。
- 把
SELECT id, name, COUNT(*) FROM user GROUP BY status改成:SELECT ANY_VALUE(id), ANY_VALUE(name), status, COUNT(*) FROM user GROUP BY status -
ANY_VALUE()要求 MySQL ≥ 5.7.5;低版本只能补全GROUP BY或用子查询 - 它不会自动利用索引优化,大表分组时可能影响性能
- 它不保证返回值和聚合结果(如
SUM(amount))来自同一行记录——这点常被误认为“取最高金额那条的 name”
临时禁用 ONLY_FULL_GROUP_BY 的正确写法
仅限开发调试或 CI 流水线跑通,生产环境慎用。断开重连即还原,不影响其他连接:
SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
- 别手拼字符串,比如
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,'—— 容易漏项,MySQL 会自动补回默认集 - 别设空值
'',MySQL 会强制恢复含ONLY_FULL_GROUP_BY的默认模式 - JDBC 的
connectionInitSql可能被忽略,建议在应用首次 query 前显式执行一次 - 关掉后,MySQL 仍可能从每组中任意选一行返回
id、name等字段——这不是 bug,是行为暴露;主从之间也可能因选行策略差异导致不一致
永久修改配置文件必须写全 sql_mode
仅限自建 MySQL,且必须重启服务才生效。在 my.cnf 的 [mysqld] 段下添加:
sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
- 必须显式列出全部项,不能省略、不能留空、不能只写
"",否则 MySQL 自动补回含ONLY_FULL_GROUP_BY的默认集 - Docker 环境需进容器编辑
/etc/mysql/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf,改完执行docker restart - Windows 是
my.ini,Linux/macOS 通常是/etc/my.cnf或/etc/mysql/my.cnf
真正容易被忽略的是:哪怕你只改了应用层 SQL,如果 ORM 底层拼的语句仍带裸字段 + GROUP BY,问题照旧。得一层层查生成逻辑,不能只盯着报错那条 SQL 看。











