MySQL 5.7+默认启用ONLY_FULL_GROUP_BY模式导致GROUP BY报错1055,非聚合列必须出现在GROUP BY子句或被聚合函数包裹,否则违反SQL标准;解决方式包括修改SQL(补全GROUP BY、用ANY_VALUE/MAX等聚合函数、窗口函数ROW_NUMBER)、临时或永久调整sql_mode配置。

为什么GROUP BY突然报错1055
因为 MySQL 5.7+ 默认启用了 ONLY_FULL_GROUP_BY 模式,不是你SQL写错了,而是数据库变“较真”了。旧环境没报错,是因为当时 sql_mode 里压根没开这个开关——它默许你从分组里随便挑一行填非聚合列,结果不可控。
典型错误信息长这样:Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'xxx.q.order_no'...。核心就一点:SELECT里出现的非聚合列(比如 order_no、name),必须要么在 GROUP BY 里,要么被 MAX()/MIN() 等聚合函数包住。
怎么改SQL才能既合法又语义正确
直接加字段进 GROUP BY 最省事,但往往不对——比如你本意是“每个会员取最新一条订单”,而 GROUP BY m.id, q.order_no 会把同个会员的多条订单全拆开,失去分组意义。
- 用聚合函数明确指定取值逻辑:比如要最新记录,就写
MAX(q.created_at)配合q.order_no→ 但注意MAX(q.order_no)不等于“最新那条的 order_no”,得用关联子查询或窗口函数 - 真正要“每组取一行”的场景,优先考虑
ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)(MySQL 8.0+),比硬凑GROUP BY更可靠 - 老版本(
临时禁用 ONLY_FULL_GROUP_BY 的风险
执行 SET SESSION sql_mode = 'STRICT_TRANS_TABLES,...' 能立刻让旧SQL跑起来,但别以为问题解决了——只是把隐患从报错变成静默错误。
- 同一个查询,在不同索引、不同数据量、不同MySQL版本下,可能返回完全不同的
order_no或pay_status -
ORDER BY q.created_at DESC在GROUP BY里不生效,排序发生在分组之后,无法保证取到的是最新记录 - 团队协作时,别人看到你这段SQL,没法一眼判断它实际返回哪条数据,维护成本飙升
永久关闭 only_full_group_by 的操作要点
修改 my.cnf(Linux)或 my.ini(Windows)里的 [mysqld] 段,关键不是删掉 ONLY_FULL_GROUP_BY,而是**完整替换整个 sql_mode 值**:
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
常见坑:
- 复制网上方案时漏掉
NO_AUTO_CREATE_USER(MySQL 5.7.12+ 必须显式声明,否则启动失败) - 改完没重启 MySQL 服务,配置根本不加载
- 只改了
@@session.sql_mode,误以为全局生效,其实只影响当前连接
改完务必验证:SELECT @@GLOBAL.sql_mode; 输出里不能再有 ONLY_FULL_GROUP_BY。


















