mysql 8.0升级后group by报错因默认启用only_full_group_by,需确保select列在group by中或用聚合函数/any_value()包裹;json_contains等函数需降级为json_search或json_extract;排序规则变更影响查询结果,建议显式指定collate;无主键表触发隐式row_id冲突,迁移前须补主键。

MySQL 5.7 升级到 8.0 后 GROUP BY 报错怎么办
直接报错 Expression #1 of SELECT list is not in GROUP BY clause,不是配置能绕过去的——8.0 默认启用了更严格的 sql_mode=ONLY_FULL_GROUP_BY。
根本原因是:5.7 可能默许“选了非分组字段但没聚合”,8.0 要求所有 SELECT 列要么在 GROUP BY 中,要么被 MIN()/MAX()/ANY_VALUE() 包裹。
- 别急着关
ONLY_FULL_GROUP_BY,它暴露的是真实语义模糊问题 - 优先重构 SQL:明确你要的值来源,比如用
MAX(created_at)替代裸列created_at - 真要临时兼容,改全局变量风险大,建议只对当前会话设:
SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY','')); -
ANY_VALUE()是 5.7.5+ 加入的合法兜底函数,比关模式安全,但得确认业务逻辑不依赖该字段的“确定性”
MySQL 8.0 的 JSON_CONTAINS 在 5.7 上跑不了怎么换
5.7 虽有 JSON 类型和基础函数,但 JSON_CONTAINS、JSON_OVERLAPS 等是 8.0 新增的,直接执行会报 FUNCTION xxx.JSON_CONTAINS does not exist。
这不是语法糖问题,是底层函数缺失,必须降级等价实现。
- 简单场景(查单个值):用
JSON_SEARCH(json_col, 'one', 'target_value') IS NOT NULL替代JSON_CONTAINS(json_col, '"target_value"') - 含嵌套对象时,
JSON_SEARCH不够用,得拆成JSON_EXTRACT+ 字符串匹配,比如:JSON_EXTRACT(json_col, '$.tags[0]') = '"hot"',但要注意数组长度和空值 - 避免用
LIKE '%\"hot\"%'这类字符串暴力匹配——JSON 格式变体(空格、转义)会导致漏判 - 如果项目已大量依赖 8.0 JSON 函数,回退成本高,建议在应用层做适配封装,而不是硬改 SQL
从 MySQL 5.6 迁移时 utf8mb4 排序规则不一致导致查询结果不同
5.6 默认用 utf8mb4_general_ci,8.0 改为 utf8mb4_0900_as_cs(大小写敏感、口音敏感),同一个 ORDER BY name,返回顺序可能翻转。
不只是显示问题,WHERE name = 'ABC' 在区分大小写的排序规则下会忽略 'abc',而老规则可能命中。
- 检查表和列的
COLLATION:SHOW CREATE TABLE t;,重点看COLLATE后缀 - 批量统一改用旧规则(不推荐长期用):
ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; - 更稳妥的做法:显式指定排序规则,比如
ORDER BY name COLLATE utf8mb4_general_ci,让行为可预期 - 应用层做字符串比较时,别依赖数据库默认规则,尤其涉及登录、权限校验等逻辑
MySQL 8.0 的隐藏主键 row_id 和 5.6 的自增逻辑冲突
8.0 引入了无主键表的隐式 row_id(6 字节递增),而老版本依赖显式 AUTO_INCREMENT 主键。迁移后如果忘了加主键,INSERT 可能因 row_id 溢出或重复导致唯一键冲突。
现象是插入突然报 Duplicate entry 'xxx' for key 'PRIMARY',但查不到对应记录——其实是隐式 row_id 绕过了你的主键约束。
- 迁移前强制检查:用
SELECT table_name FROM information_schema.tables WHERE table_schema = 'db' AND table_name NOT IN (SELECT table_name FROM information_schema.key_column_usage WHERE constraint_name = 'PRIMARY'); - 哪怕业务上真不需要主键,也显式定义一个
BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,禁用隐式row_id - 不要依赖
row_id做业务逻辑,它不可见、不可索引、不可预测 - 备份恢复时注意
mysqldump默认不导出隐式主键,跨版本还原容易丢一致性
版本差异最麻烦的从来不是语法报错,而是“看起来正常跑着,但某天某个条件触发了语义偏移”。多查 information_schema,少信文档里的“向后兼容”四个字。











