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模式分为ANSI(宽松模式)、STRICT_TRANS_TABLES(严格模式)、TRADITIONAL。这三种组合模式可用角色和权限的关系来理解。
等同于REAL_AS_FLOAT、PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE和ANSI组合模式,这种模式使语法和行为更符合标准的SQL。
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”被截掉了)。
#查看目前的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)
该模式将“||”视为字符串连接操作符(和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