mysql 8.0 group by 报错不是语法错误,而是因默认启用 only_full_group_by 模式,强制要求 select 中非聚合列必须出现在 group by 子句或用聚合函数/any_value() 处理;“expression #2”指 select 列表中第 2 个未被聚合也未分组的字段,如 select id, product, sum(amount) from orders group by user_id 中的 product 字段。

不是语法错误,是 SQL 语义校验变严格了——MySQL 8.0 默认启用 ONLY_FULL_GROUP_BY 模式,直接拒绝执行“非聚合列未出现在 GROUP BY 中且未用聚合函数包裹”的查询。
报错信息里 “Expression #2” 到底指什么?
它明确告诉你:SELECT 列表中第 2 个字段(从 1 开始数)出问题了。比如这条语句:
SELECT id, product, SUM(amount) FROM orders GROUP BY user_id;
其中 id 是 Expression #1,product 是 Expression #2 —— 它们既没在 GROUP BY 里,也没被 MAX()、ANY_VALUE() 等函数处理,MySQL 8.0 就会立刻报错。
- 错误提示一定包含
Expression #N of SELECT list is not in GROUP BY clause - 还会附带
nonaggregated column 'db.table.col'和not functionally dependent这两段关键描述 - 注意:ORDER BY 中引用非 GROUP BY 字段也会触发同样报错,常被忽略
为什么 5.7 不报,8.0 就报?
不是版本 bug,是行为收敛:MySQL 5.7.5+ 其实已默认启用 ONLY_FULL_GROUP_BY,但很多旧环境手动关掉了它(比如 sql_mode 里压根没这串),升级到 8.0 后配置重置或继承更严格的默认值,问题就暴露了。
- 5.6 或关闭该模式的 5.7 实例,会“随机选一行”的
id或product返回,结果不可预测 - 8.0 对“函数依赖”判断更严:即使你写了
GROUP BY user_id,如果表没显式主键或唯一约束,user_id仍可能不被认为能唯一确定product - 云数据库(如阿里云 RDS)升级后默认沿用 8.0 严格模式,本地开发库却可能是宽松配置,导致测试漏掉
ANY_VALUE() 能不能直接套上去?
可以,但得确认业务是否真接受“任意值”。ANY_VALUE() 是 MySQL 5.7.5+ 提供的合法函数,作用是显式声明:“我知道这列在组内不唯一,我接受不确定性”。
- 写法示例:
SELECT ANY_VALUE(id), ANY_VALUE(product), user_id, SUM(amount) FROM orders GROUP BY user_id; - 它不会让优化器做函数依赖推断,大表上可能影响性能
- 如果
product和user_id实际是一对一映射(比如用户状态码和名称),用ANY_VALUE()反而掩盖建模缺陷,应补全GROUP BY或加唯一约束 - 它不保证返回值和
SUM(amount)来自同一行记录——这点常被误认为“取最高金额那条的 product”,实际不是
临时禁用 ONLY_FULL_GROUP_BY 的风险在哪?
禁用后 SQL 能跑通,但结果依然随机,且隐患更隐蔽:
- 同一分组下多条记录的
id值不同,MySQL 可能某次选第一行、下次选最后一行,线上报表数据突然跳变 - 主库和从库因存储引擎或执行路径差异,选出的“代表行”不同,导致主从不一致
- 后续迁移到 PostgreSQL 或升级到更高 MySQL 版本时,问题会再次爆发,且更难回溯
- 云数据库通常不开放
SET GLOBAL sql_mode权限,只能走控制台参数模板,修改需审核且影响所有连接
最易被忽略的一点:即使关掉 ONLY_FULL_GROUP_BY,MySQL 也**不会保证返回哪一行**——这个“任意性”由底层引擎决定,不是可控逻辑。











