必须改SQL而非禁用ONLY_FULL_GROUP_BY,这是最稳妥解法;MySQL 5.7.5+/8.0默认启用该模式,要求SELECT中非聚合字段必须出现在GROUP BY中或用ANY_VALUE()等包裹,否则报错。

必须改SQL,而不是关ONLY_FULL_GROUP_BY——这是最稳妥的解法。 升级后报错集中在GROUP BY、INSERT缺默认值、函数声明不合规三类,根源都在sql_mode默认值收紧。临时调低模式能跑通,但掩盖逻辑缺陷,后续查bug会更难。
GROUP BY报错:Expression #2 of SELECT list is not in GROUP BY clause
这是升级后最常见错误,直接对应ONLY_FULL_GROUP_BY启用。MySQL 8.0不再容忍SELECT user_id, product, SUM(amount) FROM orders GROUP BY user_id这类写法——product既没进GROUP BY,也没套聚合函数。
- 优先重构SQL:把非聚合字段加进
GROUP BY,或用MAX(product)、ANY_VALUE(product)包裹 - 别依赖
ANY_VALUE()当兜底:它只是绕过检查,不代表业务逻辑正确;若product在分组内实际有多个值,结果不可控 - 临时禁用仅限验证:用
SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', ''));测通路,但上线前必须回滚并修复SQL
INSERT报错:Field doesn't have a default value 或 Incorrect datetime value
根源是STRICT_TRANS_TABLES默认启用。5.7宽松模式下允许INSERT INTO t(a) VALUES (1)(b为NOT NULL但无默认值),8.0直接拒绝。
- 逐表检查:
SHOW CREATE TABLE t;确认所有NOT NULL字段是否定义了DEFAULT,尤其注意TIMESTAMP字段(5.7允许NULL,8.0要求显式DEFAULT CURRENT_TIMESTAMP) - 补默认值要匹配语义:比如
status TINYINT NOT NULL不能随便填DEFAULT 0,得看业务是否真把0视为空值 - 零日期
'0000-00-00'必须清理:8.0严格模式下它非法,要么转成NULL,要么用有效日期替代
存储过程/函数创建失败:log_bin_trust_function_creators=0
不是sql_mode问题,但常被归到同一类兼容性坑里。8.0开启binlog后,默认禁止创建未声明特性的函数(如DETERMINISTIC),防止主从不一致。
- 修复方式只有两个:在函数定义中明确加上
DETERMINISTIC、NO SQL或READS SQL DATA,例如CREATE FUNCTION f() RETURNS INT DETERMINISTIC RETURN 1; -
SET GLOBAL log_bin_trust_function_creators = 1是危险开关,只应在导入阶段临时打开,事后立刻关掉 - ORM生成的函数(如Hibernate的
@Formula)容易漏声明,需人工补全特性标记
真正麻烦的不是报错本身,而是那些没报错却行为偏移的地方:比如ORDER BY在utf8mb4_0900_as_cs排序规则下大小写敏感了,缓存key拼接结果变了;或者STR_TO_DATE('2023-02-30', '%Y-%m-%d')从前返回NULL,现在直接报错。这些不会打断部署,但会让数据对不上——得靠全量SQL回归测试才能揪出来。


















