zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    C# 3.0新特性之扩展方法
    ObservableCollection 类
    Path的Data
    INotifyPropertyChanged 接口
    Django的最佳系统结构
    Django 结构及处理流程分析
    django最佳实践:项目布局
    近期的几个ASP.NET开发经验总结和收集(一)
    Javascript对象Clone
    ASP.NET20 自定义配置节学习笔记(一)
  • 原文地址:https://www.cnblogs.com/huige185/p/13948910.html
Copyright © 2011-2022 走看看