百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

一文弄懂 MySQL 中的 SQL_MODE

wptr33 2025-02-11 13:45 32 浏览

QL_MODE 是 MySQL 数据库中的一个系统变量,用于控制 MySQL 如何处理 SQL 语句和数据校验。它可以看作是一组约束和规范,确保数据的准确性、完整性和一致性。例如,可以控制如何处理无效日期、是否允许插入不完整的记录、是否区分大小写等。

作者:许祥,爱可生 MySQL DBA 团队成员,负责处理客户 MySQL 及我司自研 DMP 平台日常运维中的问题。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 2600 字,预计阅读需要 8 分钟。

什么是 SQL_MODE?

SQL_MODE 是 MySQL 数据库中的一个系统变量,用于控制 MySQL 如何处理 SQL 语句和数据校验。它可以看作是一组约束和规范,确保数据的准确性、完整性和一致性。例如,可以控制如何处理无效日期、是否允许插入不完整的记录、是否区分大小写等。

在 MySQL 中,通过设置 SQL_MODE 可以解决下面几类问题:

  1. 完成不同严格程度的数据校验,有效地保障数据准确性
  2. 保证大多数 SQL 符合标准的 SQL 语法,这样应用在不同数据库之间进行迁移时,则不需要对业务 SQL 进行较大的修改。
  3. 在不同数据库之间进行数据迁移之前,通过设置 SQL_MODE 可以使 MySQL 上的数据更方便地迁移到目标数据库中

通过阅读本文,你将收获以下知识点:

  1. MySQL 不同版本的默认 SQL_MODE 值
  2. 常用的 SQL_MODE 设置及其含义
  3. SQL_MODE 在数据迁移中的关键作用

SQL_MODE 有哪些值?

MySQL 5.7 的默认值和描述

  • ONLY_FULL_GROUP_BY:在 GROUP BY 子句中没有出现的列,若出现在 SELECT 列表、HAVING 条件、ORDER BY 条件中时会被拒绝。
  • STRICT_TRANS_TABLES:非法日期,超过字段长度的值插入时,直接报错,拒绝执行。例如,如果向一个整数列插入超出范围的值,将触发错误。
  • NO_ZERO_DATE:针对日期 '0000-00-00',执行逻辑如下:
  • disable:可以正常插入,没有警告。
  • enable:可以正常插入,有警告。
  • 如果 SQL_MODE 中包含 STRICT TRANS TABLES,则日期被拒绝写入,但可以通过加 IGNORE 关键字写入 '0000-00-00',有警告。
  • NO_ZERO_IN_DATE:日期中针对月份和日期部分,如果为 0,比如 '2024-00-00',有不同的执行逻辑:
  • disable:可以正常插入,实际插入值还是 '2024-00-00' 没有警告。
  • enable:可以正常插入,有警告。
  • 如果 SQL_MODE 中包含 STRICT TRANS TABLES 则日期被拒绝写入,但可以通过加 IGNORE 关键字写入 '0000-00-00'。
  • ERROR_FOR_DIVISION_BY_ZERO:除数为 0(包括 MOD (N,0)),执行逻辑如下:
  • disable:插入 NULL,没有警告。
  • enable:插入 NULL,有警告。
  • 如果 SQL_MODE 中包含 STRICTTRANSTABLES,则数据被拒绝写入,但可以通过加 IGNORE 关键字写入 NULL,有警告。
  • NO_AUTO_CREATE_USER:防止使用不带密码子句的 GRANT 语句来创建一个用户。
  • NO_ENGINE_SUBSTITUTION:执行 CREATE TABLE 或者 ALTER TABLE 语句时,如果指定的存储引擎不可用,MySQL 会抛出错误,而不是使用默认存储引擎。
  • disable:CREATE TABLE 会自动替换后执行,ALTER TABLE 不会执行,两个命令都有警告。
  • enable:两个命令直接报错。

MySQL 8.0 的默认值和描述

  • STRICT_TRANS_TABLES:同 MySQL 5.7,确保插入或更新的数据严格符合表的定义。
  • NO_ZERO_DATE:同 MySQL 5.7,禁止日期字段为 '0000-00-00',要求输入有效的日期。
  • NO_ZERO_IN_DATE:同 MySQL 5.7,禁止日期或日期时间字段中的月份或日部分为零。
  • ERROR_FOR_DIVISION_BY_ZERO:同 MySQL 5.7,当除以零时,MySQL 将抛出错误,而不是返回 NULL。
  • NO_AUTO_CREATE_USER:同 MySQL 5.7,禁止通过 GRANT 语句自动创建用户。
  • NO_ENGINE_SUBSTITUTION:同 MySQL 5.7,确保指定的存储引擎必须存在,不会自动替换。

查询 SQL_MODE

-- MySQL 5.7
mysql> show variables like 'sql_mode';
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                                                                     |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| sql_mode      | ONLY_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 |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

-- MySQL 8.0
mysql> show variables like 'sql_mode';
+---------------+-----------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                                                 |
+---------------+-----------------------------------------------------------------------------------------------------------------------+
| sql_mode      | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+---------------+-----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

SQL_MODE 常见设置模式

SQL_MODE 的常见设置模式是一组可以选择的选项,这些选项可以根据需要组合使用,以改变数据库的行为。以下是一些常见的模式及其含义:

  • ANSI 模式:宽松模式,对插入数据进行校验,如果不符合定义类型或长度,对数据类型调整或截断保存,报 WARNING 警告。
  • STRICT_TRANS_TABLES 模式:严格模式,进行数据的严格校验,错误数据不能插入,报 ERROR 错误。只对支持事务的表有效。
  • STRICT_ALL_TABLES 模式:严格模式,进行数据的严格校验,错误数据不能插入,报 ERROR 错误。对所有表都有效。
  • TRADITIONAL 模式:严格模式,当向 MySQL 数据库插入数据时,进行数据的严格校验,保证错误数据不能插入,报 ERROR 错误。用于事务时,会进行事务的回滚。

在下面的例子中,观察一下非法日期 “2007-04-31”(因为 4 月没有 31 日)在不同 SQL_MODE 下能否正确插入。


mysql> select @@session.sql_mode;
+-------------------------------------------------------------------------------------------------------------------------------------------+
| @@session.sql_mode                                                                                                                        |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| ONLY_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 |
+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> set session sql_mode='ANSI';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select @@session.sql_mode;
+--------------------------------------------------------------------------------+
| @@session.sql_mode                                                             |
+--------------------------------------------------------------------------------+
| REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI |
+--------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql>  create table t_sql_mode_ansi(d datetime);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t_sql_mode_ansi values('2007-04-31');
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from t_sql_mode_ansi;
+---------------------+
| d                   |
+---------------------+
| 0000-00-00 00:00:00 |
+---------------------+
1 row in set (0.00 sec)

mysql> set session sql_mode='TRADITIONAL';
Query OK, 0 rows affected, 1 warning (0.00 sec)

 mysql> select @@session.sql_mode;
+------------------------------------------------------------------------------------------------------------------------------------------------------+
| @@session.sql_mode                                                                                                                                   |
+------------------------------------------------------------------------------------------------------------------------------------------------------+
| STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> insert into t_sql_mode_ansi values('2007-04-31');
ERROR 1292 (22007): Incorrect datetime value: '2007-04-31' for column 'd' at row 1

很显然,在 ANSI 模式下,非法日期可以插人,但是插入值却变为 “0000-00-00 00:00:00” 并且系统给出了 WARNING;而在 TRADITIONAL 模式下,会直接提示日期非法,拒绝插入。STRICT_TRANS_TABLES 模式和 STRICT_ALL_TABLES 模式同样如此。

SQL_MODE 在迁移中的用法

当从 MySQL 迁移到其他异构数据库时,SQL_MODE 的配置和调整在数据迁移过程中起着关键作用。 由于不同数据库系统在 SQL 标准、数据类型处理、错误处理等方面存在差异,正确使用 SQL_MODE 可以帮助确保迁移过程中数据的完整性和一致性。

SQL_MODE 是 MySQL 的一个配置选项,控制着 SQL 语句的解析和执行方式。

例如,SQL_MODE 可以影响 NULL 值的处理、日期格式的验证、GROUP BY 的严格性等。当迁移数据到其他数据库时,目标数据库可能不支持或以不同方式处理这些规则,因此在迁移前需要仔细配置和测试 SQL_MODE。

1. SQL_MODE 在迁移前的调整

在将 MySQL 数据库迁移到其他数据库之前,可以考虑以下步骤来调整 SQL_MODE,以减少迁移时可能出现的兼容性问题:

  • 禁用严格模式:在迁移前,禁用 MySQL 中的严格模式(如 STRICT_TRANS_TABLES)可以帮助识别哪些数据在当前配置下可能会在目标数据库中引发问题。通过禁用严格模式,可以提前发现并处理不兼容的数据。
SET GLOBAL SQL_MODE ='';
  • 禁用 ONLY_FULL_GROUP_BY:MySQL 的 ONLY_FULL_GROUP_BY 模式要求所有非聚合列必须在 GROUP BY 子句中,这在其他数据库中可能不是必需的。禁用该模式可以确保 SQL 查询在目标数据库中能正确执行。
  • 启用宽松模式:通过设置较为宽松的 SQL_MODE(如禁用 NO_ZERO_DATE、NO_ZERO_IN_DATE),可以让 MySQL 接受一些可能在目标数据库中允许的数据格式,并确保这些数据能被顺利迁移。

2. 在迁移过程中处理 SQL_MODE 相关问题

  • 日期和时间处理:一些数据库系统对日期和时间有更严格的要求。例如,0000-00-00 这样的日期在 MySQL 中可能是合法的,但在其他数据库中会引发错误。在迁移前,需要确保数据格式符合目标数据库的要求,或者通过 SQL 脚本清理这些数据。
  • 空字符串与 NULL 的处理:在 MySQL 中,空字符串和 NULL 可能在一些情况下被视为相等,而在其他数据库中并非如此。迁移前,应该明确这些字段的逻辑,并在必要时进行转换。
  • 标识符大小写:MySQL 对标识符的大小写敏感性可能与目标数据库不同。在迁移前,使用 SQL_MODE 的 ANSI_QUOTES 选项可以确保标识符的引用方式符合 SQL 标准,并减少在目标数据库中的兼容性问题。

3. 迁移后的兼容性测试

完成数据迁移后,需要在目标数据库中进行全面的兼容性测试,以确保迁移后的数据和应用程序能正常运行。重点测试的领域包括:

  • 查询结果的准确性:检查涉及 GROUP BY、聚合函数、日期处理等 SQL 查询是否在目标数据库中返回预期结果
  • 数据完整性:确保迁移后的数据没有丢失、截断或被错误转换。
  • 性能:有些 SQL_MODE 设置可能影响查询性能,迁移后需要在目标数据库中优化相关查询。

4. 小结

在从 MySQL 迁移到其他数据库时,合理调整 SQL_MODE 可以显著减少迁移过程中的兼容性问题。通过禁用严格模式、调整日期和空值处理、确保标识符的一致性,以及进行全面的测试,可以确保迁移后的数据和应用程序在新的数据库环境中稳定运行。

5. 迁移过程中需要注意

在数据迁移过程中,可以设置 SQL_MODE 为 NO_TABLE_OPTIONS 模式。这样将去掉 SHOW CREATE TABLE 中的 ENGINE 关键字,获得通用的建表脚本。

测试示例如下:

mysql> show create table test\G
*************************** 1. row ***************************
       Table: test
Create Table: CREATE TABLE `test` (
  `ename` varchar(10) COLLATE utf8mb4_bin DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `sal` decimal(10,2) DEFAULT NULL,
  `hiredate` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
1 row in set (0.00 sec)
mysql>
mysql> set session sql_mode='NO_TABLE_OPTIONS';
Query OK, 0 rows affected, 2 warnings (0.00 sec)

mysql>
mysql> show create table test\G
*************************** 1. row ***************************
       Table: test
Create Table: CREATE TABLE `test` (
  `ename` varchar(10) COLLATE utf8mb4_bin DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `sal` decimal(10,2) DEFAULT NULL,
  `hiredate` date DEFAULT NULL
)
1 row in set (0.00 sec)

总结

  1. SQL_MODE 的 “严格模式” 为 MySQL 提供了很好的数据校验功能,保证了数据的准确性,TRADITIONALSTRICT_TRANS_TABLES 是常用的两种严格模式,要注意两者的区别。
  2. SQL_MODE 的多种模式可以灵活组合,组合后的模式可以更好地满足应用程序的需求。尤其在数据迁移中,SQL_MODE 的使用更为重要。

更多技术文章,请访问:https://opensource.actionsky.com/

相关推荐

什么是Java中的继承?如何实现继承?

什么是继承?...

Java 继承与多态:从基础到实战的深度解析

在面向对象编程(OOP)的三大支柱中,继承与多态是构建灵活、可复用代码的核心。无论是日常开发还是框架设计,这两个概念都扮演着至关重要的角色。本文将从基础概念出发,结合实例与图解,带你彻底搞懂Java...

Java基础教程:Java继承概述_java的继承

继承概述假如我们要定义如下类:学生类,老师类和工人类,分析如下。学生类属性:姓名,年龄行为:吃饭,睡觉老师类属性:姓名,年龄,薪水行为:吃饭,睡觉,教书班主任属性:姓名,年龄,薪水行为:吃饭,睡觉,管...

java4个技巧:从继承和覆盖,到最终的类和方法

日复一日,我们编写的大多数Java只使用了该语言全套功能的一小部分。我们实例化的每个流以及我们在实例变量前面加上的每个@Autowired注解都足以完成我们的大部分目标。然而,有些时候,我们必须求助于...

java:举例说明继承的概念_java继承的理解

在现实生活中,继承一般指的是子女继承父辈的财产。在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系。例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物,同理,...

从零开始构建一款开源的 Vibe Coding 产品 Week1Day4:业界调研之 Agent 横向对比

前情回顾前面两天我们重点调研了了一下Cursor的原理和Cursor中一个关键的工具edit_file的实现,但是其他CodingAgent也需要稍微摸一下底,看看有没有优秀之处,下...

学会这几个插件,让你的Notepad++使用起来更丝滑

搞程序开发的小伙伴相信对Notepad++都不会陌生,是一个占用空间少、打开启动快的文件编辑器,很多程序员喜欢使用Notepad++进行纯文本编辑或者脚本开发,但是Notepad++的功能绝不止于此,...

将 node_modules 目录放入 Git 仓库的优点

推荐一篇文章Whyyoushouldcheck-inyournodedependencies[1]...

再度加码AI编程,腾讯发布AI CLI并宣布CodeBuddy IDE开启公测

“再熬一年,90%的程序员可能再也用不着写for循环。”凌晨两点半,王工还在公司敲键盘。他手里那份需求文档写了足足六页,产品经理反复改了三次。放在过去,光数据库建表、接口对接、单元测试就得写两三天。现...

git 如何查看stash的内容_git查看ssh key

1.查看Stash列表首先,使用gitstashlist查看所有已保存的stash:...

6万星+ Git命令懒人必备!lazygit 终端UI神器,效率翻倍超顺手!

项目概览lazygit是一个基于终端的Git命令可视化工具,通过简易的TUI(文本用户界面)提升Git操作效率。开发者无需记忆复杂命令,即可完成分支管理、提交、合并等操作。...

《Gemini CLI 实战系列》(一)Gemini CLI 入门:AI 上命令行的第一步

谷歌的Gemini模型最近热度很高,而它的...

deepin IDE新版发布:支持玲珑构建、增强AI智能化

IT之家8月7日消息,深度操作系统官方公众号昨日(8月6日)发布博文,更新推出新版deepin集成开发环境(IDE),重点支持玲珑构建。支持玲珑构建deepinIDE在本次重磅更...

狂揽82.7k的star,这款开源可视化神器,轻松创建流程图和图表

再不用Mermaid,你的技术文档可能已经在悄悄“腐烂”——图表版本对不上、同事改完没同步、评审会上被一句“这图哪来的”问得哑口无言。这不是危言耸听。GitHub2025年开发者报告显示,63%的新仓...

《Gemini CLI 实战系列》(五)打造专属命令行工具箱

在前几篇文章中,我们介绍了GeminiCLI的基础用法、效率提升、文件处理和与外部工具结合。今天我们进入第五篇...