• mysql SQL_MODE设置


    1.1.   SQL_MODE设置

             在生产环境中强烈建议将这个值设置为严格模式,这样有些问题可以在数据库的设计和开发阶段就能实现,而如果在生产环境下运行数据库后发现这类问题,那么修改的代价将变得十分巨大。此外正确地设置sql_mode还可以做一些约束(constraint)检查的工作。

             对于sql_mode的设置,可以在配置文件、客户端、当前会话或者全局会话中设置。

    查看sql_mode的设置情况:

    mysql>select @@global.sql_mode;

    +--------------------------------------------+

    |@@global.sql_mode                         |

    +--------------------------------------------+

    |STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |

    +--------------------------------------------+

    1 row inset (0.00 sec)


    mysql>select @@session.sql_mode;

    +--------------------------------------------+

    |@@session.sql_mode                        |

    +--------------------------------------------+

    |STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |

    +--------------------------------------------+

    1 row inset (0.00 sec)

    1.1.1.     STRICT_TRANS_TABLES

             严格模式是指将sql_mode变量设置为STRICT_TRANS_TABLES或STRICT_ALL_TABLES中的至少一种

             STRICT_TRANS_TABLES:在该模式下,如果一个值不能插入到一个事务表,则中断当前的操作不影响非事务表(例如表的存储引擎为myisam);

    1.1.2.     ALLOWS_INVALID_DATES

             该选项并不完全对日期的合法性进行检查,只检查月份是否在1-12之间,日期是否在1-31之间。该模式仅对date和datetime类型有效,而对timestamp无效,因为timestamp总是要求一个合法的输入。

    1.1.3.     ANSI_QUOTES

             启用ANSI_QUOTES后,不能使用双引号来引用字符串,因为它将被解释为识别符。

    mysql>create table z(a varchar(10))engine=innodb;

    Query OK,0 rows affected (0.02 sec)


    mysql>insert into z select "aaa";

    Query OK,1 row affected (0.01 sec)

    Records:1  Duplicates: 0  Warnings: 0


    mysql>set sql_mode='ANSI_QUOTES';

    Query OK,0 rows affected (0.00 sec)


    mysql>insert into z select "aaa";

    ERROR1054 (42S22): Unknown column 'aaa' in 'field list'

    mysql>

    1.1.4.     ERROR_FOR_DIVISION_BY_ZERO

             在insert或者update过程中,如果数据被零除(或MOD(X,0))则产生错误(否则为警告)。如果未给出该模式,那么数据被零除时,mysql返回NULL。如果用到INSERT IGNORE或者UPDATE IGNORE中,mysql生成被零除警告,但操作结果为NULL。

    1.1.5.     HIGH_NOT_PRECEDENCE

             启用HIGH_NOT_PRECEDENCE:操作符的优先顺序表达式。例如not a between b and c被解释为NOT (a between a and b)。启用HIGH_NOT_PRECEDENCE SQL模式,可以获得以前版本的更高优先级的结果。

    mysql>select 0 between -1 and 1;

    +--------------------+

    | 0between -1 and 1 |

    +--------------------+

    |                  1 |

    +--------------------+

    1 row inset (0.00 sec)


    mysql>select not 0 between -1 and 1;

    +------------------------+

    | not 0between -1 and 1 |

    +------------------------+

    |                      0 |

    +------------------------+

    1 row inset (0.00 sec)

    mysql>set sql_mode='high_not_precedence';

    Query OK,0 rows affected (0.00 sec)


    mysql>select 0 between -1 and 1;

    +--------------------+

    | 0between -1 and 1 |

    +--------------------+

    |                  1 |

    +--------------------+

    1 row inset (0.01 sec)


    mysql>select not 0 between -1 and 1;

    +------------------------+

    | not 0between -1 and 1 |

    +------------------------+

    |                      1 |

    +------------------------+

    1 row inset (0.00 sec)

             被解释为(not 0) between -1 and 1结果完全相反。

    1.1.6.     ignore_space

             忽略函数名和括号之间的空格:

    mysql>select max(a) from t;

    +--------+

    | max(a)|

    +--------+

    |    105 |

    +--------+

    1 row inset (0.00 sec)

    mysql>select max (a) fromt;

    ERROR1630 (42000): FUNCTION test.max does not exist. Check the 'Function NameParsing and Resolution' section in the Reference Manual

    mysql>set sql_mode='ignore_space';

    Query OK,0 rows affected (0.00 sec)


    mysql>select max (a) from t;

    +---------+

    | max (a)|

    +---------+

    |     105 |

    +---------+

    1 row inset (0.00 sec)


    1.1.7.     NO_AUTO_CREATE_USER

             禁止grant创建密码为空的用户

    mysql>select @@sql_mode;

    +---------------------+

    |@@sql_mode          |

    +---------------------+

    |NO_AUTO_CREATE_USER |

    +---------------------+

    1 row inset (0.00 sec)


    mysql>set sql_mode='';

    Query OK,0 rows affected (0.00 sec)


    mysql>grant all privileges on *.* to gf@'%';

    Query OK,0 rows affected (0.00 sec)


    mysql>set sql_mode='NO_AUTO_CREATE_USER';

    Query OK,0 rows affected (0.00 sec)


    mysql>grant all privileges on *.* to gf1@'%';

    ERROR1133 (42000): Can't find any matching row in the user table

    mysql>grant all privileges on *.* to gf1@'%' identified by 123456;

    ERROR1064 (42000): You have an error in your SQL syntax; check the manual thatcorresponds to your MySQL server version for the right syntax to use near'123456' at line 1

    mysql>grant all privileges on *.* to gf5@'%' identified by 123456;

    ERROR1064 (42000): You have an error in your SQL syntax; check the manual thatcorresponds to your MySQL server version for the right syntax to use near'123456' at line 1


    1.1.8.     NO_AUTO_VALUE_ON_ZERO

             该选项影响列为自增长的插入。在默认设置下,插入0或者null代表生成下一个自增长值。如果用户希望插入的值为0,而该列又是自增长的,那么这个选项就有用了。

    mysql>create table tt(id int primary key auto_increment);

    Query OK,0 rows affected (0.02 sec)


    mysql>explain ttG;

    ***************************1. row ***************************

      Field: id

       Type: int(11)

       Null: NO

        Key: PRI

    Default:NULL

      Extra: auto_increment

    1 row inset (0.00 sec)


    ERROR:

    No queryspecified


    mysql>insert into tt values(0);

    Query OK,1 row affected (0.02 sec)


    mysql>insert into tt values(null);

    Query OK,1 row affected (0.00 sec)


    mysql>insert into tt values(5);

    Query OK,1 row affected (0.00 sec)


    mysql>select * from tt;

    +----+

    | id |

    +----+

    |  2 |

    |  4 |

    |  5 |

    +----+

    3 rows inset (0.00 sec)


    mysql>set sql_mode='no_auto_value_on_zero';

    Query OK,0 rows affected (0.00 sec)


    mysql>truncate table tt;

    Query OK,0 rows affected (0.01 sec)


    mysql>insert into tt values(0);

    Query OK,1 row affected (0.01 sec)


    mysql>insert into tt values(null);

    Query OK,1 row affected (0.00 sec)


    mysql>insert into tt values(5);

    Query OK,1 row affected (0.01 sec)


    mysql>select * from tt;

    +----+

    | id |

    +----+

    |  0 |

    |  2 |

    |  5 |

    +----+

    3 rows inset (0.01 sec)

             只是对0插入有效。

    1.1.9.     NO_BACKSLASH_ESCAPES

             反斜杠“”作为普通字符而非转义字符:

    mysql>set sql_mode='NO_BACKSLASH_ESCAPES';

    Query OK,0 rows affected (0.00 sec)


    mysql>select '\'G;

    ***************************1. row ***************************

    \: \

    1 row inset (0.00 sec)


    ERROR:

    No queryspecified


    mysql>set sql_mode='';

    Query OK,0 rows affected (0.00 sec)


    mysql>select '\'G;

    ***************************1. row ***************************

    :

    1 row inset (0.00 sec)

    1.1.10. NO_DIR_IN_CREATE

             在创建表时忽视所有INDEXDIRETORY和DATA DIRECTORY的选项。

    1.1.11. NO_ENGINE_SUBSTITUTION

             如果需要的存储引擎被禁用或者未编译,那么抛出错误。

    1.1.12. NO_UNSIGNED_SUBSTITUTION

             启用这个选项后,两个UNSIGNED类型相减返回SIGNED类型。

    1.1.13. NO_ZERO_DATE

             在非严格模式下,可以插入形如“00-00-0000:00:00”的非法日期,mysql仅抛出一个警告,而启用该选项后,mysql不允许插入零日期,插入0日期会抛出错误而非警告。

    mysql>set sql_mode='no_zero_date,strict_trans_tables';

    Query OK,0 rows affected, 1 warning (0.00 sec)


    mysql>insert into tt values(null,'00-00-00 00:00:00');

    ERROR1292 (22007): Incorrect datetime value: '00-00-00 00:00:00' for column 'date'at row 1

    mysql>insert into tt values(null,'2014-12-02 00:00:00');

    Query OK,1 row affected (0.01 sec)


    mysql>select * from tt;

    +----+---------------------+

    | id |date                |

    +----+---------------------+

    |  0 | NULL                |

    |  2 | NULL                |

    |  5 | NULL                |

    |  6 | NULL                |

    |  8 | 0000-00-00 00:00:00 |

    | 10 |0000-00-00 00:00:00 |

    | 12 |0000-00-00 00:00:00 |

    | 14 |2014-12-02 00:00:00 |

    +----+---------------------+

    8 rows inset (0.00 sec)

             注意一定是在strict_trans_tables,否则只是警告:

    mysql>set sql_mode='no_zero_date';

    Query OK,0 rows affected, 1 warning (0.00 sec)


    mysql>insert into tt values(null,'00-00-00 00:00:00');

    Query OK,1 row affected, 1 warning (0.00 sec)

    mysql>show warnings;

    +---------+------+-----------------------------------------------+

    | Level   | Code | Message                                       |

    +---------+------+-----------------------------------------------+

    | Warning| 1264 | Out of range value for column 'date' at row 1 |

    +---------+------+-----------------------------------------------+

    1 row inset (0.00 sec)


    mysql>select * from tt;

    +----+---------------------+

    | id |date                |

    +----+---------------------+

    |  0 | NULL                |

    |  2 | NULL                |

    |  5 | NULL                |

    |  6 | NULL                |

    |  8 | 0000-00-00 00:00:00 |

    | 10 |0000-00-00 00:00:00 |

    +----+---------------------+

    6 rows inset (0.00 sec)

    1.1.14. NO_ZERO_IN_DATE

             在严格模式下,不允许日期和月份为零:采用日期和月份为零的格式时mysql会直接抛出错误而非警告:

    mysql>set sql_mode='NO_ZERO_IN_DATE';

    Query OK,0 rows affected, 1 warning (0.00 sec)


    mysql>TRUNCATE TABLE tt;

    Query OK,0 rows affected (0.00 sec)


    mysql>insert into tt values(null,'2014-12-02 00:00:00');

    Query OK,1 row affected (0.00 sec)


    mysql>insert into tt values(null,'2014-12-00 00:00:00');

    Query OK,1 row affected, 1 warning (0.00 sec)


    mysql>show warnings;

    +---------+------+-----------------------------------------------+

    |Level   | Code | Message                                       |

    +---------+------+-----------------------------------------------+

    | Warning| 1264 | Out of range value for column 'date' at row 1 |

    +---------+------+-----------------------------------------------+

    1 row in set(0.00 sec)


    mysql>select * from tt;

    +----+---------------------+

    | id |date                |

    +----+---------------------+

    |  1 | 2014-12-02 00:00:00 |

    |  2 | 0000-00-00 00:00:00 |

    +----+---------------------+

    2 rows inset (0.00 sec)


    mysql>set sql_mode='NO_ZERO_IN_DATE,strict_trans_tables';

    Query OK,0 rows affected, 1 warning (0.00 sec)


    mysql>insert into tt values(null,'2014-12-00 00:00:00');

    ERROR1292 (22007): Incorrect datetime value: '2014-12-00 00:00:00' for column 'date'at row 1

    mysql>

    1.1.15. ONLY_FULL_GROUP_BY

             对于GROUP by聚合操作,如果在select中的列没有在GROUP BY中出现,那么sql语句是不合法的,因为a列不在group by从句中。

    mysql>select id,sum(date) from tt group by date;

    +----+----------------+

    | id |sum(date)      |

    +----+----------------+

    |  2 |              0 |

    |  1 | 20141202000000 |

    +----+----------------+

    2 rows inset (0.00 sec)


    mysql>set sql_mode='ONLY_FULL_GROUP_BY';

    Query OK,0 rows affected (0.00 sec)


    mysql>select id,sum(date) from tt group by date;

    ERROR1055 (42000): 'gf.tt.id' isn't in GROUP BY

    mysql>

    1.1.16. PAD_CHAR_TO_FULL_LENGTH

             对于char类型,不要截断空洞数据。空洞数据就是自动填充值为0x20的数据。

             默认情况下:

    mysql>create table ttt(a char(5));

    Query OK,0 rows affected (0.01 sec)


    mysql>insert into ttt select 'a';

    Query OK,1 row affected (0.00 sec)

    Records:1  Duplicates: 0  Warnings: 0


    mysql>select a,char_length(a),hex(a) from ttt;

    +------+----------------+--------+

    | a    | char_length(a) | hex(a) |

    +------+----------------+--------+

    | a    |              1 | 61     |

    +------+----------------+--------+

    1 row inset (0.00 sec)

             默认字符长度为1,数据库对后面的空洞数据进行了截断。

    mysql>set sql_mode='pad_char_to_full_length';

    Query OK,0 rows affected (0.00 sec)


    mysql>select a,char_length(a),hex(a) from ttt;

    +-------+----------------+------------+

    | a     | char_length(a) | hex(a)     |

    +-------+----------------+------------+

    | a     |              5 | 6120202020 |

    +-------+----------------+------------+

    1 row inset (0.00 sec)

             反映的是实际存储的内容。

    1.1.17. PIPES_AS_CONCAT

             将“||”视为字符串的联接操作符而非运算符,这个和oracle数据库是一样的,也和字符串的拼接函数concat相类似。

    mysql>select 'a'||'b'||'c';

    +---------------+

    |'a'||'b'||'c' |

    +---------------+

    |             0 |

    +---------------+

    1 row inset, 3 warnings (0.00 sec)


    mysql>show warnings;

    +---------+------+---------------------------------------+

    |Level   | Code | Message                               |

    +---------+------+---------------------------------------+

    | Warning| 1292 | Truncated incorrect DOUBLE value: 'a' |

    | Warning| 1292 | Truncated incorrect DOUBLE value: 'b' |

    | Warning| 1292 | Truncated incorrect DOUBLE value: 'c' |

    +---------+------+---------------------------------------+

    3 rows inset (0.00 sec)


    mysql>set sql_mode='pipes_as_concat';

    Query OK,0 rows affected (0.00 sec)


    mysql>select 'a'||'b'||'c';

    +---------------+

    |'a'||'b'||'c' |

    +---------------+

    |abc           |

    +---------------+

    1 row inset (0.00 sec)


    1.1.18. REAL_AS_FLOAT

             将real视为float的同义词而不是double的同义词。

    1.1.19. STRICT_ALL_TABLES

             对所有引擎的表都启用严格模式。STRICT_TRANS_TABLES只对支持事务的表启用严格模式。

             在严格模式下,一旦任何操作的数据产生问题,都会终止当前的操作。

             对于启用STRICT_ALL_TABLES选项的非事务引擎来说,这时数据可能停留在一个未知的状态,这可能不是所有非事务引擎原意看到的一种情况,因此需要非常小心这个选项可能带来的潜在影响。

    1.1.20. SQL_MODE的选项组合
    名称
    等同于选项
    ANSI
    REAL_AS_FLOAT、PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE
    ORACLE
    REAL_AS_FLOAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NP_TABLE_OPTIONS、NO_FIELD_OPTIONS、NO_AUTO_CREATE_USER
    TRADITIONAL
    STRICT_TRANS_TABLES、STRICT_ALL_TABLES、NO_ZERO_DATE、NO_ZERO_IN_DATE、ERROT_FOR_DIVIDION_BY_ZERO、NO_ AUTO_CREATE_USER、NO_ENGINE_SUBSTITITION
    MSSQL
    PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NP_TABLE_OPTIONS、NO_FIELD_OPTIONS
    DB2
    PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NP_TABLE_OPTIONS、NO_FIELD_OPTIONS
    MYSQL323
    NO_FIELD_OPTIONS、HIGH_NOT_PRECEDENCE
    MYSQL40
    NO_FIELD_OPTIONS、HIGH_NOT_PRECEDENCE
    MAXDB
    PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NP_TABLE_OPTIONS、NO_FIELD_OPTIONS、NO_AUTO_CREATE_USER
     
     
     
  • 相关阅读:
    Java并发之Thread类的使用
    剑指Offer
    总结下2017之前的几年
    解决一个特定的负载均衡下定时任务执行多次的问题
    《MYSQL》----字符串的复杂函数,检索的七-天-排-重
    科学计数法的转换
    小伙伴自言自语发给我的聊天记录,一句都看不懂
    记录下一个让我调了一天的失误
    记录一个从没见过的bug
    吐槽下
  • 原文地址:https://www.cnblogs.com/yuyue2014/p/5213057.html
Copyright © 2020-2023  润新知