MySQL的SQL模式sql_mode

一、默认的SQL模式

  MySQL 8.0的默认SQL模式为:ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

  ONLY_FULL_GROUP_BY:使用group by时,select的字段必须在group by指定的列。例如“select a,b from tableName group by a;”在非ONLY_FULL_GROUP_BY模式下是允许的,但在ONLY_FULL_GROUP_BY模式下是不允许。

  STRICT_TRANS_TABLES:事务性存储引擎以及可能的情况下为非事务性存储引擎启用严格的SQL模式。具体下面介绍。

  NO_ZERO_IN_DATE:支持 0000-00-00 0000-01-01 (年月日都为0,月日不为0)

  NO_ZERO_DATE :支持 1000-00-00 0000-01-00 0000-00-01(年月日中任何一个不为0)

  ERROR_FOR_DIVISION_BY_ZERO:该模式影响除以零的处理。如果未启用此模式,则除以零将插入 NULL并且不产生警告。如果启用此模式,则除以零将插入 NULL并产生警告。如果启用了此模式和严格模式,则除非另外IGNORE 指定,否则除以零会产生错误。对于INSERT IGNORE 和UPDATE IGNORE,除以零将插入NULL并产生警告。

  NO_ENGINE_SUBSTITUTION:当诸如CREATE TABLE或ALTER TABLE指定的存储引擎被禁用或未编译时,控制默认存储引擎的自动替换。

 

二、组合SQL模式

  组合SQL模式分为ANSI(宽松模式)、STRICT_TRANS_TABLES(严格模式)、TRADITIONAL。这三种组合模式可用角色和权限的关系来理解。

1、ANSI(宽松模式)

  等同于REAL_AS_FLOAT、PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE和ANSI组合模式,这种模式使语法和行为更符合标准的SQL。

2、STRICT_TRANS_TABLES(严格模式)

  STRICT_TRANS_TABLES是严格模式,不允许非法日期,也不允许超过字段长度的值插入字段中,对于插入不正确的值给出错误而不是警告。

  不是严格模式时,插入超过字段定义时,值会被截断为表定义的字段长度,同时会提示waring。

例如:

#查看目前的sql模式(以下是MySQL8.0.19默认的sql mode,注意默认是严格模式)
root@localhost|test>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 |
+---------------+-----------------------------------------------------------------------------------------------------------------------+

#创建测试表
root@localhost|test>create table eric(id int primary key auto_increment, name varchar(10), create_time datetime);
Query OK, 0 rows affected (0.03 sec)

#插入name字段长度为11字符的值
root@localhost|test>insert into eric(id, name, create_time) values(1,'0123456789a', now());
ERROR 1406 (22001): Data too long for column 'name' at row 1
root@localhost|test>
#可见严格模式下直接报错不准插入

#我们修改本session的sql_mode,把STRICT_TRANS_TABLES去掉(其它不变)
root@localhost|test>set session sql_mode='ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
Query OK, 0 rows affected, 1 warning (0.00 sec)

#再次插入相同的sql
root@localhost|test>insert into eric(id, name, create_time) values(1,'0123456789a', now());
Query OK, 1 row affected, 1 warning (0.00 sec)
root@localhost|test>show warnings;
+---------+------+-------------------------------------------+
| Level   | Code | Message                                   |
+---------+------+-------------------------------------------+
| Warning | 1265 | Data truncated for column 'name' at row 1 |
+---------+------+-------------------------------------------+
1 row in set (0.00 sec)
#可以看到插入成功,但有warning提示数据被截断

root@localhost|test>select * from eric;
+----+------------+---------------------+
| id | name       | create_time         |
+----+------------+---------------------+
|  1 | 0123456789 | 2020-03-30 01:42:32 |
+----+------------+---------------------+
1 row in set (0.00 sec)
#可以看到插入的结果中被截为10位字符(插入sql的那个“a”被截掉了)。
若设置了STRICT_TRANS_TABLES,应该同时设置NO_ZERO_DATE、NO_ZERO_IN_DATE和ERROR_FOR_DIVISION_BY_ZERO,这三个参数在MySQL8.0.19时还需要单独设置,在以后的版本中将会合并到严格模式。
 

3、TRADITIONAL

  使MySQL表现得像“ 传统的 ” SQL数据库系统。当在列中插入错误的值时,此模式的简单描述是 “ 给出错误而不是警告 ”。
  TRADITIONAL相当于STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO,和 NO_ENGINE_SUBSTITUTION。
  STRICT_ALL_TABLES:MySQL返回错误,并忽略其余行。但是,由于已插入或更新了较早的行,因此结果是部分更新。为避免这种情况,请使用单行语句,该语句可以在不更改表的情况下中止。
  STRICT_TRANS_TABLES:MySQL将无效值转换为该列的最接近有效值,并插入调整后的值。如果缺少值,MySQL将为列数据类型插入隐式默认值。无论哪种情况,MySQL都会生成警告而不是错误,并继续处理该语句。
 

三、使用适当的SQL模式进行数据迁移或导入

1、NO_BACKSLASH_ESCAPES模式

  启用NO_BACKSLASH_ESCAPES模式,使反斜线成为普能字符。在导入数据时,如果数据中含有反斜线字符,启用该模式可以保证导入数据的正确性。
#查看目前的sql模式(目前是默认模式)
root@localhost|test>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)

#尝试插入带返斜线的数据
root@localhost|test>insert into t values(1,'abc\def');
Query OK, 1 row affected (0.00 sec)
#查询发现返斜线不见了
root@localhost|test>select * from t;
+------+--------+
| id   | name   |
+------+--------+
|    1 | abcdef |
+------+--------+
1 row in set (0.00 sec)

#把模式改为NO_BACKSLASH_ESCAPES模式
root@localhost|test>set sql_mode='NO_BACKSLASH_ESCAPES';
Query OK, 0 rows affected (0.00 sec)
#再次插入id为2,name字段值相同的数据
root@localhost|test>insert into t values(2,'abc\def'); 
Query OK, 1 row affected (0.00 sec)
#查询发现第二条数据插入正确
root@localhost|test>select * from t;
+------+---------+
| id   | name    |
+------+---------+
|    1 | abcdef  |
|    2 | abc\def |
+------+---------+
2 rows in set (0.00 sec)

2、PIPES_AS_CONCAT模式

  该模式将“||”视为字符串连接操作符(和concat功能一样),在Oracle等数据中,“||”被视为字符串的连接操作符,所以,在其他数据库中含有“||”操作符的SQL在MySQL将无法执行,为解决此问题,MySQL引入此模式。

#查看目前的sql模式(目前是默认模式)
root@localhost|test>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)

root@localhost|test>select 'ab'||'cd';
+------------+
| 'ab'||'cd' |
+------------+
|          0 |
+------------+
1 row in set, 3 warnings (0.00 sec)
#设置模式为PIPES_AS_CONCAT
root@localhost|test>set sql_mode='PIPES_AS_CONCAT';
Query OK, 0 rows affected (0.00 sec)
#“||”和Oracle效果一样了
root@localhost|test>select 'ab'||'cd';
+------------+
| 'ab'||'cd' |
+------------+
| abcd       |
+------------+
1 row in set (0.00 sec)

 

详情请参考官档:https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html

 

你可能感兴趣的:(MySQL,mysql)