三十五、MySQL基础系列笔记之SQL Mode

作者: 温新

分类: 【MySql】

阅读: 2082

时间: 2021-01-11 14:21:19

什么是SQL Mode(SQL模式)

SQL Mode是一组MySql支持的基本语法、数据校验的规则。

SQL Mode解决如下问题

  • 设置SQL Mode,用于完成不同严格程度的数据校验,有效的保障数据准确性;
  • 设置SQL Mode为ANSI模式,用于保证大多数SQL符合标准的SQL语法,可应用于不同数据库之间的迁移;
  • 在不同数据库之间进行数据迁移之前,通过设置SQL Mode可以使MySQL上的数据更方便地迁移到目标数据库中。

SQL Mode

sql_mode值 含义
ONLY_FULL_GROUP_BY 在group by子句中未出现的列出现在select列表、having条件、order by条件中时会被拒绝
STRICT_TRANS_TABLES 非法日期;超过字段长度的值插入时,直接报错,拒绝执行
NO_ZERO_IN_DATE 日期中针对月份和日期部分,若为0,如'2021-00-00',执行不同的逻辑disable:可以正常插入,实际值为'2021-00-00'无警告enable:可以正常插入,有警告;若mode中含STRICT_TRANS_TABLES,则日期被拒绝写入,但可通过加ignore关键字写入'0000-00-00'
NO_ZERO_DATE 针对日期'0000-00-00',执行如下逻辑disable:可正常插入,无警告enable:可正常插入,有警告。若mode中含STRICT_TRANS_TABLES,则日期被拒绝写入,但可通过加ignore写入'0000-00-00',有警告。
ERROR_FOR_DIVISION_BY_ZERO 除数为0(包含MOD(N,0)),执行如下逻辑:disable:插入NULL,无警告enable:插入NULL,有警告。若mode中含STRICT_TRANS_TABLES,则数据拒绝被写入,但可通过加ignore写入null,有警告。
NO_AUTO_CREATE_USER 防止使用不带密码子句的grant语句来创建一个用户
NO_ENGINE_SUBSTITUTION 执行create table或alter table语句时,若指定不支持的存储引擎,是否自动替换为默认的存储引擎。disable:create table会自动替换后执行;alter table不会执行;两个命令都有警告;enable:两个命令直接报错。

举个栗子用于理解SQL Mode,来看看如下字段,长度为2

create table t2(name varchar(2));

MySQL5.7之前的版本,对于插入3个字是不会报错的,可以插入进去,但是MySQL5.7之后的版本则会直接报错。来看实际案例。

mysql> insert into t2 (name) values ('你好');
Query OK, 1 row affected (0.00 sec)

# 可以看到,一旦超过3个字将直接报错
mysql> insert into t2 (name) values ('你好ya');
ERROR 1406 (22001): Data too long for column 'name' at row 1

SQL Mode演示

还是基于上面的t2表,演示不同的SQL Mode的效果。

案例一:取消sql mode

set session sql_mode='';

# 查看是否设置成功
mysql> select @@sql_mode;
+------------+
| @@sql_mode |
+------------+
|            |
+------------+
1 row in set (0.00 sec)

插入一条超过字段长度限制的数据。

mysql> insert into t2 values('你好呀');      
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from t2;
+--------+
| name   |
+--------+
| h2     |
| 你好   |
| 你好   |
+--------+
3 rows in set (0.00 sec)

可以看到,超过字段长度的数据插入成功,没有报错,但是超过长度的数据被截断了。

案例二:STRICT_TRANS_TABLES(严格事务表模式)

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

mysql> insert into t2 values('自如初');
ERROR 1406 (22001): Data too long for column 'name' at row 1

可以看到,设置为STRICT_TRANS_TABLES模式时,超过字段长度的数据插入时将会报错。

关于修改sql_mode的方法,即设置当前会话或全局模式,具体可以参考 MySQL基础系列笔记之变量 这篇文章;本篇文章还是简单记录一下:

修改sql_mode的方式,set [global|session] sql_mode='modes'

session表示只在本次连接中生效;global表示在本次连接中并不生效,而对于新的连接生效。关于其他模式,多多练习。

案例三:ANSI模式

验证日期合法性。2021-02-30这个日期是错误的,2月没有30号。

create table `t3`(d datetime);
# 修改模式
mysql> set session sql_mode='ANSI';
Query OK, 0 rows affected (0.00 sec)

# 插入数据
mysql> insert into t3 values('2021-02-30');
Query OK, 1 row affected, 1 warning (0.00 sec)

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

可以神奇的看到,非法日期被插入成功了,但是,查询出来的日期值却变成了'0000-00-00 00:00:00'。

案例四:TRADITIONAL模式

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

mysql> insert into t3 values('2021-02-30');
ERROR 1292 (22007): Incorrect datetime value: '2021-02-30' for column 'd' at row 1


mysql> insert into t3 values('2021-02-28');
Query OK, 1 row affected (0.00 sec)

该模式下,非法日期将无法插入。

常用的SQL Mode

sql_mode值 含义
ANSI 等同于 REAL_AS_FLOAT、PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、ONLY_FULL_GROUP_BY、ANSI的组合,该模式遇到异常时倾向于警告而非立即报错。
STRICT_TRANS_TABLES 该模式适用于事务表和非事务表,是严格模式,不允许非法日期及超过字段长度的值插入;对于插入不正确值直接报错而非警告。
TRADITIONAL 等同于 STRICT_TRANS_TABLES、STRICT_ALL_TABLES、NO_ZERO_IN_DATE、NO_ZERO_DATE、ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER、NO_ENGINE_SUBSTITUTION的组合,是严格模式,对插入不正确值直接报错。

2021-01-11

请登录后再评论