MySQL学习笔记之sql_mode

一、什么是服务器SQL模式:

  MySQL服务器可以在不同的SQL模式下运行,并且可以根据sql_mode系统变量的值将这些模式应用于不同的客户端,
  DBA可以设置全局SQL模式以匹配站点服务器操作要求,并且每个应用程序可以根据自己的要求设置session SQL模式。
  SQL模式会影响MySQL支持的SQL语法以及它执行的数据验证检查,这使得在不同环境中使用MySQL以及将MySQL与其他数据库服务一起使用更加容易。
  在使用InnoDB表时,还要考虑innodb_strict_mode系统变量,它启用了对InnoDB表的其他错误检查。

二、SQL模式查看和设置:

  查看当前SQL模式:
        select @@global.sql_mode;
        select @@session.sql_mode;
        select @@sql_mode; #等同于select @@session.sql_mode;
  设置SQL模式:
        set global sql_mode = "modes";
        set session sql_mode = "modes";
        永久保存设置SQL模式:
        在MySQL配置文件(Linux:my.cnf,Windows:my.ini)中的[mysqld]最后一行添加:sql_mode="modes",重启MySQL服务

三、SQL模式说明:

  MySQL8.0默认的SQL模式有:ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
SQL模式 说明
ALLOW_INVALID_DATES 不完全检查日期,只检查月份是否在112之间,日期是否在131之间。此模式适用于date和datetime列,不适用于需要验证有效日期的列(timestamp)。禁用此模式后,服务器要求月和日的值是合法的,而不仅仅是112和131。非严格模式下,无效日期(如"2020-04-30")将转换为"0000-00-00",并生成警告。严格模式下,无效日期将报错,若要允许这样的无效日期,需要启用此模式
ANSI_QUOTES 该模式下将"看成了标识引号符(类似于 符号),而不是字符串引号符。启用此模式后,仍可使用符号作为标识引号符,但是不能使用双引号来引用文本字符串了,因为双引号被解释成标识引号符。
ERROR_FOR_DIVISION_BY_ZERO 严格模式下,在insert或update操作过程中,如果除以零(包括使用函数mod(M,0))将会报除以零错误,非严格模式下则会产生警告。如果未启用该模式除以零将插入null,并不会产生警告,启用该模式除以零将插入null,并产生警告。如果同时启用了该模式和严格模式,除零将会产生错误,若使用了insert ignore和update ignore将插入null并产生警告。对于select操作,除零将返回null并产生警告(无论是否启用严格模式)。不推荐使用该模式,该模式不是严格模式的一部分,但应与严格模式结合使用,默认是启用该模式的。如果在未启用严格模式是启用了该模式将会发出警告。
high_not_precedence 在启用该模式时,表达式 select not a between b and c 被解析成 select (not a) between b and c,未启用该模式时被解析成 select not (a between b and c)
ignore_space 该模式允许函数名和()之间有空格,将导致内置函数名被视为保留字。例如,MySQL中有count()函数,在创建数据表count时:create table count (id int);将会报错:ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'count (i int)' at line 1。这时表名必须使用``引起来:create table count (i int);该模式适用于内置函数,而不适用于用户自定义函数。
no_auto_value_on_zero 在该模式下,auto_incremnet列只能通过插入null来生成下一个序列号,未启用该模式可以通过插入null或0来生成下一个序列号。如果表中auto_increment列已经有0了,该模式将非常有用(不建议存储0)。例如,如果您使用mysqldump转储表,然后重新加载它,那么当遇到0值时,MySQL通常会生成新的序列号,从而导致表的内容与转储的表不同。在重新加载转储文件之前,该模式可以解决此问题。因此,mysqldump会在其输出中自动包含一个启用该模式的语句。
no_backslash_escapes 启用该模式,反斜杠()将被视为普通字符,而非转义字符
no_dir_in_create 创建表时,忽略所有索引目录和数据目录指令。此选项在副本服务器上很有用。
no_engine_subtitution 当create table 或 alter table 等语句指定的存储引擎已禁用或未编译时,将自动替换默认存储引擎。默认该模式是启用的。启用该模式时,如果所需的存储引擎不可用,则会发生错误,并且不会创建或更新表。禁用该模式时,create table时会使用默认存储引擎,若默认存储引擎不可用,则会报警告,alter table时会报警告,并且不会更改表。
no_unsigned_subtraction 禁用此模式时,整数之间的进行减法运算时(其中一个为无符号类型),默认生成的结果是无符号类型的。如果结果为负数,将会报错。如果此类操作的结果用于更新无符号整数列,则结果将被剪裁为列类型的最大值,若启用了该模式,则将结果裁剪成0,如果启用了严格模式,将报错,列不会发生改变,进行减法运算时,结果仅为signed(无论减号两边是有符号类型的还是unsigned或者signed)。
no_zero_date 未启用该模式时,'0000-00-00'则允许并且插入不会产生警告。如果启用此模式,'0000-00-00' 则允许并插入将产生警告。若果启用了严格模式和该模式,插入'0000-00-00'将会报错,若此时使用了insert ignore和update ignore '0000-00-00'将会被插入,但会产生警告。该模式不推荐使用,它不是严格模式的一部分,但应与严格模式结合使用,并且默认情况下处于启用状态。如果该模式在未启用严格模式的情况下启用了,将会产生警告。
no_zero_in_date 在严格模式,不接受月或日部分为0的日期。如果使用IGNORE选项,我们为类似的日期插入'0000-00-00'。在非严格模式,可以接受该日期,但会生成警告。
only_full_group_by 在此模式下,如果select列表中出现了group by未使用到的字段(使用聚合函数除外),将会报错。
pad_char_to_full_length 启用该模式时,检索char类型的字符时将不会自动去掉字符后面的空格。禁用该模式时,将自动去掉char类型字符后面的空格。该模式对varchar类型的字符不起作用。
pipes_as_concat
peal_as_float 默认情况下,MySQL将peal视为double的同义词,启用该模式时,将peal视为float。
strict_all_tables 为所有存储引擎启用严格模式,拒绝无效数据。
strict_trans_tables 为事务存储引擎启用严格的SQL模式,并在可能的情况下为非Transaction存储引擎启用严格SQL模式。
time_truncate_fractional 当插入带小数的time,date或timestamp类型的值时,MySQL默认是四舍五入的,启用该模式时,直接截取要保留的小数位。
ansi 相当于peal_as_float, pipes_as_concat,ansi_quotes, ignore_space,和 onli_full_group_by。
traditional 相当于STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, 和 NO_ENGINE_SUBSTITUTION
四、测试sql_mode对SQL语句执行的影响
  1. allow_invalid_dates:
        mysql> create table t1(c1 date,c2 timestamp,c3 datetime);
        Query OK, 0 rows affected (0.03 sec)

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

        mysql> insert into t1(c1,c2,c3) values('2020-04-31','2020-04-31','2020-04-31');
        Query OK, 1 row affected, 3 warnings (0.00 sec)

        mysql> select * from t1;
        +------------+---------------------+---------------------+
        | c1         | c2                  | c3                  |
        +------------+---------------------+---------------------+
        | 0000-00-00 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |
        +------------+---------------------+---------------------+
        1 row in set (0.00 sec)

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

        mysql> insert into t1(c1,c2,c3) values('2020-04-31','2020-04-31','2020-04-31');
        ERROR 1292 (22007): Incorrect date value: '2020-04-31' for column 'c1' at row 1

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

        mysql> insert into t1(c1,c2,c3) values('2020-04-31','2020-04-31','2020-04-31');
        Query OK, 1 row affected, 1 warning (0.01 sec)

        mysql> select * from t1;
        +------------+---------------------+---------------------+
        | c1         | c2                  | c3                  |
        +------------+---------------------+---------------------+
        | 0000-00-00 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |
        | 2020-04-31 | 0000-00-00 00:00:00 | 2020-04-31 00:00:00 |
        +------------+---------------------+---------------------+
        2 rows in set (0.00 sec)
  2. ansi_quotes:
        mysql> set sql_mode='';
        Query OK, 0 rows affected (0.00 sec)

        mysql> select "a";
        +---+
        | a |
        +---+
        | a |
        +---+
        1 row in set (0.00 sec)

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

        mysql> select "a";
        ERROR 1054 (42S22): Unknown column 'a' in 'field list'

  3. error_for_division_zero:
        mysql> create table t2(c1 int);
        Query OK, 0 rows affected (0.02 sec)

        mysql> insert into t2 values(7/0);
        Query OK, 1 row affected (0.00 sec)

        mysql> select * from t2;
        +------+
        | c1   |
        +------+
        | NULL |
        +------+
        1 row in set (0.00 sec)

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

        mysql> insert into t2 values(7/0);
        Query OK, 1 row affected, 1 warning (0.01 sec)

        mysql> select * from t2; 
        +------+
        | c1   |
        +------+
        | NULL |
        | NULL |
        +------+
        2 rows in set (0.00 sec)

        mysql> select 7/0;
        +------+
        | 7/0  |
        +------+
        | NULL |
        +------+
        1 row in set, 1 warning (0.00 sec)

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

        mysql> select 7/0;
        +------+
        | 7/0  |
        +------+
        | NULL |
        +------+
        1 row in set, 1 warning (0.00 sec)

        mysql> insert into t2 values(7/0); 
        ERROR 1365 (22012): Division by 0

        mysql> insert ignore t2 values(7/0);
        Query OK, 1 row affected, 1 warning (0.01 sec)

        mysql> select * from t2;
        +------+
        | c1   |
        +------+
        | NULL |
        | NULL |
        | NULL |
        +------+
        3 rows in set (0.00 sec)

  4. high_not_precedence:
        mysql> set sql_mode='';
        Query OK, 0 rows affected (0.00 sec)

        mysql> select not 1 between -5 and 5;
        +------------------------+
        | not 1 between -5 and 5 |
        +------------------------+
        |                      0 |
        +------------------------+
        1 row in set (0.00 sec)

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

        mysql> select not 1 between -5 and 5;
        +------------------------+
        | not 1 between -5 and 5 |
        +------------------------+
        |                      1 |
        +------------------------+
        1 row in set (0.00 sec)

  5. ignore_space:
        mysql> set sql_mode='';
        Query OK, 0 rows affected (0.00 sec)

        mysql> create table count (id int);
        Query OK, 0 rows affected (0.02 sec)

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

        mysql> create table max (id int);
        ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'max (id int)' at line 1
        mysql> create table `max` (id int);
        Query OK, 0 rows affected (0.03 sec)
  6. no_auto_value_on_zero:
        mysql> create table t3(id int primary key auto_increment,name varchar(15));
              Query OK, 0 rows affected (0.03 sec)

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

        mysql> insert into t3(id,name) values(null,'aaa');
        Query OK, 1 row affected (0.00 sec)

        mysql> select * from t3;
        +----+------+
        | id | name |
        +----+------+
        |  1 | aaa  |
        +----+------+
        1 row in set (0.00 sec)

        mysql> insert into t3(id,name) values(null,'aaa');
        Query OK, 1 row affected (0.01 sec)

        mysql> select * from t3;
        +----+------+
        | id | name |
        +----+------+
        |  1 | aaa  |
        |  2 | aaa  |
        +----+------+
        2 rows in set (0.00 sec)

        mysql> insert into t3(id,name) values(0,'aaa');
        Query OK, 1 row affected (0.01 sec)

        mysql> select * from t3;
        +----+------+
        | id | name |
        +----+------+
        |  1 | aaa  |
        |  2 | aaa  |
        |  3 | aaa  |
        +----+------+
        3 rows in set (0.00 sec)

        mysql> insert into t3(id,name) values(0,'aaa');
        Query OK, 1 row affected (0.00 sec)

        mysql> select * from t3;
        +----+------+
        | id | name |
        +----+------+
        |  1 | aaa  |
        |  2 | aaa  |
        |  3 | aaa  |
        |  4 | aaa  |
        +----+------+
        4 rows in set (0.00 sec)

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

        mysql> insert into t3(id,name) values(null,'aaa');
        Query OK, 1 row affected (0.00 sec)

        mysql> select * from t3;
        +----+------+
        | id | name |
        +----+------+
        |  1 | aaa  |
        |  2 | aaa  |
        |  3 | aaa  |
        |  4 | aaa  |
        |  5 | aaa  |
        +----+------+
        5 rows in set (0.00 sec)

        mysql> insert into t3(id,name) values(0,'aaa');
        Query OK, 1 row affected (0.00 sec)

        mysql> select * from t3;
        +----+------+
        | id | name |
        +----+------+
        |  0 | aaa  |
        |  1 | aaa  |
        |  2 | aaa  |
        |  3 | aaa  |
        |  4 | aaa  |
        |  5 | aaa  |
        +----+------+
        6 rows in set (0.00 sec)

        mysql> insert into t3(id,name) values(0,'aaa');
        ERROR 1062 (23000): Duplicate entry '0' for key 't3.PRIMARY'
  7. no_backslash_escapes:
        mysql> set sql_mode='';
        Query OK, 0 rows affected (0.00 sec)

        mysql> select '\a';
        +---+
        | a |
        +---+
        | a |
        +---+
        1 row in set (0.00 sec)

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

        mysql> select '\a';
        +----+
        | \a |
        +----+
        | \a |
        +----+
        1 row in set (0.00 sec)

  8. no_zero_date:
        mysql> create table t6(c1 date);
        Query OK, 0 rows affected (0.03 sec)

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

        mysql> insert into t6 values('0000-00-00');
        Query OK, 1 row affected (0.01 sec)

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

        mysql> insert into t6 values('0000-00-00'); 
        Query OK, 1 row affected, 1 warning (0.01 sec)

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

        mysql> insert into t6 values('0000-00-00');
        ERROR 1292 (22007): Incorrect date value: '0000-00-00' for column 'c1' at row 1
        mysql> insert ignore into t6 values('0000-00-00');
        Query OK, 1 row affected, 1 warning (0.00 sec)

        mysql> select * from t6;
        +------------+
        | c1         |
        +------------+
        | 0000-00-00 |
        | 0000-00-00 |
        | 0000-00-00 |
        +------------+
        3 rows in set (0.00 sec)

  9. no_zero_in_date:
        mysql> set sql_mode='';
        Query OK, 0 rows affected (0.00 sec)

        mysql> insert into t6 values('2020-00-00');
        Query OK, 1 row affected (0.00 sec)

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

        mysql> insert into t6 values('2020-00-00');
        Query OK, 1 row affected, 1 warning (0.01 sec)

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

        mysql> insert into t6 values('2020-00-00');
        ERROR 1292 (22007): Incorrect date value: '2020-00-00' for column 'c1' at row 1
        mysql> select * from t6;
        +------------+
        | c1         |
        +------------+
        | 0000-00-00 |
        | 0000-00-00 |
        | 0000-00-00 |
        | 2020-00-00 |
        | 0000-00-00 |
        +------------+
        5 rows in set (0.00 sec)

  10. only_full_group_by:
        mysql> select * from t1 group by c1;
        +------------+---------------------+---------------------+
        | c1         | c2                  | c3                  |
        +------------+---------------------+---------------------+
        | 0000-00-00 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |
        +------------+---------------------+---------------------+
        1 row in set, 2 warnings (0.00 sec)
        mysql> set sql_mode='only_full_group_by';
        Query OK, 0 rows affected (0.00 sec)

        mysql> select * from t1 group by c1;
        ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'testdb1.t1.c2' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

        mysql> select c1 from t1 group by c1;
        +------------+
        | c1         |
        +------------+
        | 0000-00-00 |
        +------------+
        1 row in set, 1 warning (0.00 sec)

        mysql> select count(*) from t1 group by c1;
        +----------+
        | count(*) |
        +----------+
        |        2 |
        +----------+
        1 row in set, 1 warning (0.00 sec)
  11. pad_char_to_full_length:
        mysql> create table t7(c1 char(10),c2 varchar(10));
        Query OK, 0 rows affected (0.03 sec)

        mysql> insert into t7(c1,c2) values('a      ','b      ');
        Query OK, 1 row affected (0.00 sec)

        mysql> select length(c1),c1,length(c2),c2 from t7;
        +------------+------+------------+---------+
        | length(c1) | c1   | length(c2) | c2      |
        +------------+------+------------+---------+
        |          1 | a    |          7 | b       |
        +------------+------+------------+---------+
        1 row in set (0.00 sec)

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

        mysql> select length(c1),c1,length(c2),c2 from t7;
        +------------+------------+------------+---------+
        | length(c1) | c1         | length(c2) | c2      |
        +------------+------------+------------+---------+
        |         10 | a          |          7 | b       |
        +------------+------------+------------+---------+
        1 row in set (0.00 sec)

        mysql> insert into t7(c1,c2) values('c','d');
        Query OK, 1 row affected (0.00 sec)

        mysql> select length(c1),c1,length(c2),c2 from t7;
        +------------+------------+------------+---------+
        | length(c1) | c1         | length(c2) | c2      |
        +------------+------------+------------+---------+
        |         10 | a          |          7 | b       |
        |         10 | c          |          1 | d       |
        +------------+------------+------------+---------+
        2 rows in set (0.00 sec)
  12. pipes_as_concat:
        mysql> set sql_mode='pipes_as_concat';

        mysql> select 1 || 2;
        +--------+
        | 1 || 2 |
        +--------+
        | 12     |
        +--------+
        1 row in set (0.00 sec)

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

        mysql> select 1 || 2;
        +--------+
        | 1 || 2 |
        +--------+
        |      1 |
        +--------+
        1 row in set, 1 warning (0.00 sec)
  13. time_truncate_fractional:
        MySQL8+好像不支持
        mysql> set sql_model='TIME_TRUNCATE_FRACTIONAL';
        ERROR 1193 (HY000): Unknown system variable 'sql_model'
  14. ansi:
        mysql> set sql_mode='';
        Query OK, 0 rows affected (0.00 sec)

        mysql> select @@sql_mode;
        +------------+
        | @@sql_mode |
        +------------+
        |            |
        +------------+
        1 row in set (0.00 sec)

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

        mysql> select @@sql_mode;
        +--------------------------------------------------------------------------------+
        | @@sql_mode                                                                     |
        +--------------------------------------------------------------------------------+
        | REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI |
        +--------------------------------------------------------------------------------+
        1 row in set (0.00 sec)
  15. fractional:
        mysql> set sql_mode='';
        Query OK, 0 rows affected (0.00 sec)

        mysql> select @@sql_mode;
        +------------+
        | @@sql_mode |
        +------------+
        |            |
        +------------+
        1 row in set (0.00 sec)

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

        mysql> select @@sql_mode;
        +----------------------------------------------------------------------------------------------------------------------------------+
        | @@sql_mode                                                                                                                       |
        +----------------------------------------------------------------------------------------------------------------------------------+
        | STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_ENGINE_SUBSTITUTION |
        +----------------------------------------------------------------------------------------------------------------------------------+
        1 row in set (0.00 sec)
posted @ 2020-11-16 13:41  huige185  阅读(371)  评论(0编辑  收藏  举报