mysql 8.0升级后union报error 1064,主因是rank、json等新增保留关键字导致别名/字段名冲突,须用反引号包裹或重命名;同时only_full_group_by启用引发group by报错,需修正查询逻辑而非降级sql模式。

UNION查询突然报ERROR 1064,大概率是撞了RANK或JSON
MySQL 8.0把RANK、JSON、GROUP、WINDOW等词加进了保留关键字列表,而5.7没有。如果你的UNION语句里写了SELECT id AS rank FROM t1 UNION SELECT id AS rank FROM t2,升级后直接卡在AS rank位置报错——不是语法写错,是解析器词法阶段就拒绝了。
快速验证:执行SELECT keyword FROM INFORMATION_SCHEMA.KEYWORDS WHERE RESERVE = 1 AND keyword = 'RANK';,8.0返回一行,5.7为空。
- 别名、表别名、ORDER BY字段、JOIN条件中出现这些词,全都会触发
- 大小写不敏感:
AS Rank、as json、ORDER BY group全部命中 - 动态拼SQL的场景(如报表导出)最难排查,人眼容易漏
建表或ALTER时字段名含rank/json,必须全程用反引号
列名用了rank或json,建表就会报ERROR 1064,错误提示通常指向near 'rank INT'这类位置。这不是可选操作,是硬性要求。
CREATE TABLE t1 (id INT, `rank` INT);——建表时就得包
SELECT id, `rank` FROM t1;——查的时候也得包,漏一个就错
ALTER TABLE t1 CHANGE `rank` `score` INT;——改名时新旧名都得包
- ORM如SQLAlchemy、Django默认不自动加反引号,拼SQL时必须手动处理
-
SET sql_mode = 'ANSI_QUOTES'不能绕过限制,它只让双引号支持标识符,但"rank"在DDL里依然非法 - 视图、存储过程里所有引用处都要检查,
INFORMATION_SCHEMA.VIEWS和ROUTINES可辅助扫描
GROUP BY报错Expression #1 not in GROUP BY,别急着关ONLY_FULL_GROUP_BY
8.0默认启用ONLY_FULL_GROUP_BY,而5.7默认关闭。常见报错ERROR 1055往往不是UNION本身的问题,而是UNION结果被后续GROUP BY引用时暴露的逻辑缺陷。
- 确认SELECT字段:要么出现在GROUP BY子句中,要么被
MAX()、COUNT()等聚合函数包裹 - 临时修复可用
SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));,但只是掩耳盗铃 - ORM生成的SQL(如旧版Django)可能隐含非确定性字段,必须重审查询意图,而非降级SQL模式
- UNION结果集若含聚合字段,再GROUP BY时极易触发该错误,建议先物化中间结果再分组
别名冲突比字段名更隐蔽,尤其在动态SQL和视图里
字段名冲突好查,但AS json、JOIN rank ON ...这种别名冲突常被忽略。它们不会在建表时报错,只在执行时崩,且错误位置难定位。
批量检查建议:
- 查视图定义:
SELECT TABLE_NAME, VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE VIEW_DEFINITION LIKE '%AS json%' OR VIEW_DEFINITION LIKE '%AS rank%'; - 查存储过程:
SELECT ROUTINE_NAME, ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_DEFINITION REGEXP 'AS[[:space:]]+(json|group|rank)[[:space:]]*(,|FROM|UNION|ORDER)'; - 重命名优先于反引号:
rank→ranking_val,json→payload,避免长期依赖转义符号
真正麻烦的从来不是加几对反引号,而是那些散落在动态拼接、ORM映射、历史视图里的隐式别名——它们不会在测试环境冒泡,只在上线后某个报表导出时突然炸开。











