报错确由ONLY_FULL_GROUP_BY引起,需先执行SELECT @@sql_mode验证;确认后优先用ANY_VALUE()显式表达语义,而非禁用模式或滥用MAX/MIN,临时关闭仅限调试,永久修改须完整配置sql_mode并置于[mysqld]段下。

确认报错确实是 ONLY_FULL_GROUP_BY 导致的
别急着改配置或重写 SQL,先验证是不是它在作怪。执行:SELECT @@sql_mode; 或 SELECT @@SESSION.sql_mode;。如果返回结果里包含 ONLY_FULL_GROUP_BY(通常排在最前面),且错误信息含 this is incompatible with sql_mode=only_full_group_by 或 ERROR 1055,那就锁定了。
注意:@@GLOBAL.sql_mode 是全局设置,但应用连接用的是会话级模式;云数据库(如阿里云 RDS)可能禁止修改 @@GLOBAL.sql_mode,直接执行 SET GLOBAL 会报 ERROR 1227。
优先用 ANY_VALUE() 显式表达语义
这不是“绕过”,而是告诉 MySQL:“我知道这个字段不聚合,但我接受任意一行的值”。比禁用模式更安全、更可读。
- 原报错 SQL:
SELECT user_id, product, SUM(amount) FROM orders GROUP BY user_id; - 改成:
SELECT user_id, ANY_VALUE(product), SUM(amount) FROM orders GROUP BY user_id; -
ANY_VALUE()在 MySQL 5.7.5+ 可用,语义清晰,不影响索引和性能 - 避免用
MAX(product)或MIN(product)伪装——除非你真需要最大/最小值,否则会误导后续维护者 - 如果字段有业务含义(比如取最新订单的 status),应改用窗口函数或子查询,而不是依赖
ANY_VALUE()
临时关闭 ONLY_FULL_GROUP_BY(仅限调试)
只应在本地开发、CI 测试或紧急排查时用,不能用于生产环境长期依赖。
- 正确写法是显式拼接:
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; - 别用
REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', '')—— 它会在字符串里留下多余逗号,导致整个sql_mode解析失败,MySQL 会悄悄回退到默认值(含ONLY_FULL_GROUP_BY) - 某些客户端(如 MySQL Workbench)会在连接初始化时重置
sql_mode,你手动执行的SET SESSION可能被覆盖 - 该设置只对当前连接生效,应用重启、连接池重建后就失效
永久修改配置需避开三个常见坑
改了 my.cnf 却没生效?大概率栽在这三处。
- 确认 MySQL 实际加载的配置文件路径:
mysqld --help --verbose | grep "Default options",常见位置包括/etc/my.cnf、/usr/etc/my.cnf、~/.my.cnf - 必须把
sql_mode写在[mysqld]段下,写在[client]或文件开头无效 -
sql_mode是全量覆盖字段,不能只写sql_mode = STRICT_TRANS_TABLES—— 要完整列出所有保留的模式,且明确剔除ONLY_FULL_GROUP_BY,例如:sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
真正难的不是改配置,而是判断哪些 SQL 真的需要 ANY_VALUE(),哪些其实暴露了业务逻辑缺陷——比如按用户分组却要取“某个产品名”,往往意味着数据建模或查询意图本身就有歧义。


















