前言

最近公司开发同学A在群聊中说某某系统的某条SQL有问题,抛出异常,而同样的SQL在开发同学B(SQL由B同学编写)的环境没有问题,带着好奇心我上前协助一看,最终发现异常大致内容是:sql_mode=ONLY_FULL_GROUP_BY,SQL大致类似如下格式:

SELECT name, age, SUM(sales) FROM orders GROUP BY name;  

此时让我想起了年轻的自己,当初也犯过如此问题,于是我耐心的告知开发同学B:

  • SELECT 中的非聚合字段必须出现在 GROUP BY 子句中
  • 所有非聚合字段需通过聚合函数(如MAX、MIN、SUM)处理,或显式声明分组依据

解释完毕后,开发同学B提出疑问,为什么开发同学A的环境不行,而我的就可以,于是我在他们电脑分别使用了SELECT VERSION(); 语句进行查看版本,然后告知开发同学A和开发同学B,自MySQL 5.7.5 起:官方将ONLY_FULL_GROUP_BY 加入默认的sql_mode,以增强 SQL 的标准兼容性和数据一致性,当我说完 打算扬长而去时,两位开发同学随即又抛出疑问:sql_mode是什么?我:......


简介

MySQL为了支持在不同的环境下运行,允许我们给它设置不同的运行模式(sql_mode)
sql_mode是MySQL中用于设置sql语法和行为的系统变量
控制MySQL的sql解析和执行的方式,使其与sql标准或其他数据库系统的行为一致,通过设置sql_mode,可以改变MySQL处理待定sql操作的方式


我们在安装mysql时就要确定它的运行模式(sql_mode),不建议在中途更改它的运行模式

建议在跨mysql实例备份还原数据时,保持双方mysql实例具有相同的运行模式


sql_mode模式

MySQL 支持的 sql_mode 模式

模式名含义
STRICT_TRANS_TABLES事务表中对无效数据报错,非事务表警告
STRICT_ALL_TABLES所有表对无效数据都报错
NO_ZERO_IN_DATE不允许日期中的月或日为 0(如 2023-00-10)
NO_ZERO_DATE不允许日期为 '0000-00-00'
ERROR_FOR_DIVISION_BY_ZERO除以 0 报错
NO_AUTO_CREATE_USER禁止 GRANT 自动创建用户(MySQL 8.0 移除)
NO_ENGINE_SUBSTITUTION禁止在指定引擎不可用时自动替代
ONLY_FULL_GROUP_BYGROUP BY 中必须列出所有非聚合列
ANSI_QUOTES用双引号表示标识符(字段、表名等)
PIPES_AS_CONCAT使用 “||” 表示字符串拼接
IGNORE_SPACE函数名后允许加空格
ANSI启用符合 ANSI SQL 的语法和行为
TRADITIONAL启用接近标准 SQL 的严格模式组合
NO_BACKSLASH_ESCAPES禁用反斜杠 “\” 作为转义字符
HIGH_NOT_PRECEDENCE改变 “NOT” 运算符的优先级
NO_UNSIGNED_SUBTRACTION无符号数减法结果转换为有符号类型
REAL_AS_FLOAT将 “REAL” 类型作为 “FLOAT” 处理
PAD_CHAR_TO_FULL_LENGTH使用 “CHAR” 比较时右侧填充空格至固定长度
ALLOW_INVALID_DATES允许插入无效日期(非严格模式时有效)
TIME_TRUNCATE_FRACTIONAL时间字段截断小数秒部分而非四舍五入

sql_mode对比

对比项MySQL 5.7 默认值MySQL 8.0 默认值
默认 sql_modeONLY_FULL_GROUP_BY,
STRICT_TRANS_TABLES,
NO_ZERO_IN_DATE,
NO_ZERO_DATE,
ERROR_FOR_DIVISION_BY_ZERO,
NO_AUTO_CREATE_USER,
NO_ENGINE_SUBSTITUTION
ONLY_FULL_GROUP_BY,
STRICT_TRANS_TABLES,
NO_ZERO_IN_DATE,
NO_ZERO_DATE,
ERROR_FOR_DIVISION_BY_ZERO,
NO_ENGINE_SUBSTITUTION
NO_AUTO_CREATE_USER默认启用已移除(不再支持 GRANT 创建用户)
严格性中等更严格,接近 SQL 标准

查看和修改sql_mode

sql_mode,分为全局的、会话的(即:针对当前链接有效),在mysql运行时查看和更改sql_mode的sql如下:

-- 查看当前会话的sql_mode
select @@sql_mode
SELECT @@SESSION.sql_mode;

-- 查看全局的sql_mode
SELECT @@GLOBAL.sql_mode;

-- 设置当前会话的sql_mode
set sql_mode="TRADITIONAL";
SET SESSION sql_mode = 'TRADITIONAL';

-- 设置全局的sql_mode
SET GLOBAL sql_mode = 'TRADITIONAL';

-- 添加 sql_mode
SET SESSION sql_mode = sys.list_add(@@session.sql_mode, 'ONLY_FULL_GROUP_BY');
SET GLOBAL sql_mode = sys.list_add(@@global.sql_mode, 'ONLY_FULL_GROUP_BY');

不过,上述的修改当myql服务器重启时就自动失效了,为了长久有效,我们可以在my.cnfmy.ini文件中进行配置

Last modification:May 28, 2025
如果觉得我的文章对你有用,您可以给博主买一杯果汁,谢谢!