确认是ONLY_FULL_GROUP_BY报错需先执行SELECT @@SESSION.sql_mode;若结果含该模式且错误码为1055,即坐实问题;推荐用ANY_VALUE()显式表达语义而非临时关闭或删配置。

怎么确认真是ONLY_FULL_GROUP_BY在报错
别急着改SQL或配置,先执行SELECT @@SESSION.sql_mode;。如果返回结果里含ONLY_FULL_GROUP_BY(通常在最前面),且错误信息带ERROR 1055或this is incompatible with sql_mode=only_full_group_by,就坐实了。注意:@@GLOBAL.sql_mode是全局值,但应用连接实际用的是会话级模式;云数据库(如阿里云 RDS)往往禁止修改@@GLOBAL.sql_mode,直接SET GLOBAL会报ERROR 1227。
用ANY_VALUE()显式表达语义,而不是“绕过”
这是最推荐的修复方式——不是妥协,而是把模糊逻辑写清楚。比如原SQL:SELECT user_id, product, SUM(amount) FROM orders GROUP BY user_id; 报错是因为product没聚合也没出现在GROUP BY里。改成: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可能被覆盖 - 该设置只对当前连接生效,应用重启、连接池重建后即失效
永久修改配置必须完整覆盖sql_mode
如果决定禁用,不能只删ONLY_FULL_GROUP_BY,必须提供完整、合法的sql_mode字符串,并写入[mysqld]段。
- Linux下编辑
/etc/my.cnf,Windows下改my.ini,在[mysqld]下添加:sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION - 云数据库(如RDS)需进控制台「参数设置」,搜
sql_mode,取消勾选ONLY_FULL_GROUP_BY,再重启实例 - 自建MySQL执行
SET GLOBAL sql_mode = '...';后,务必同步更新配置文件,否则服务重启就还原 - 注意:
NO_AUTO_CREATE_USER在MySQL 8.0+已被移除,若升级到8.0,需剔除该项,否则启动失败
真正容易被忽略的点是:很多老SQL在旧环境能跑,只是因为MySQL以前“睁一只眼”,结果不可预期——同一查询,不同执行计划可能取到不同行的order_no或status。用ANY_VALUE()不是让代码“能跑”,而是让它“说得清”。


















