SQL_MODE设置讲解

SQL_MODE可能是比较容易让开发人员和DBA忽略的一个变量,默认为空。SQL_MODE的设置其实是比较冒险的一种设置,因为在这种设置下 可以允许一些非法操作,比如可以将NULL插入NOT NULL的字段中,也可以插入一些非法日期,如“2012-12-32”。因此在生产环境中强烈建议开发人员将这个值设为严格模式,这样有些问题可以在数 据库的设计和开发阶段就能发现,而如果在生产环境下运行数据库后发现这类问题,那么修改的代价将变得十分巨大。此外,正确地设置SQL_MODE还可以做 一些约束(Constraint)检查的工作。

对于SQL_MODE的设置,可以在MySQL的配置文件如my.cnf和my.ini中进行,也可以在客户端工具中进行,并且可以分别进行全局的设置或当前会话的设置。下面的命令可以用来查看当前SQL_MODE的设置情况。

  1. mysql> SELECT @@global.sql_mode\G;
  2. *************************** 1. row ***************************
  3. @@global.sql_mode:
  4. 1 row in set (0.00 sec)
  5. mysql> SELECT @@session.sql_mode\G;
  6. *************************** 1. row ***************************
  7. @@session.sql_mode: NO_UNSIGNED_SUBTRACTION
  8. 1 row in set (0.00 sec)

可以看到当前全局的SQL_MODE设置为空,而当前会话的设置为NO_UNSIGNED_SUBTRACTION。通过以下语句可以将当前的SQL_MODE设置为严格模式。

  1. mysql> SET GLOBAL sql_mode=‘strict_trans_tables‘;
  2. Query OK, 0 rows affected (0.00 sec)

严格模式是指将SQL_MODE变量设置为STRICT_TRANS_TABLES或STRICT_ALL_TABLES中的至少一种。现在来看一下SQL_MODE可以设置的选项。

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

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

ANSI_QUOTES:启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它将被解释为识别符,示例如下:

  1. mysql> CREATE TABLE z ( a VARCHAR(10))ENGINE=INNODB;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql>INSERT INTO z SELECT "aaa";
  4. Query OK, 1 rows affected (0.00 sec)
  5. mysql> SET sql_mode=‘ANSI_QUOTES‘;
  6. Query OK, 0 rows affected (0.00 sec)
  7. mysql> INSERT INTO z SELECT "aaa";
  8. ERROR 1054 (42S22): Unknown column ‘aaa‘ in ‘field list‘

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

HIGH_NOT_PRECEDENCE NOT:操作符的优先顺序是表达式。例如,NOT a BETWEEN b AND c被解释为NOT(a BETWEEN b AND c),在一些旧版本MySQL中, 前面的表达式被解释为(NOT a)BETWEEN b AND c。启用HIGH_NOT_PRECEDENCE SQL模式,可以获得以前旧版本的更高优先级的结果。下面看一个例子:

  1. mysql> SELECT 0 BETWEEN -1 AND 1\G;
  2. *************************** 1. row ***************************
  3. 0 BETWEEN -1 AND 1: 1
  4. 1 row in set (0.00 sec)

0在-1到1之间,所以返回1,如果加上NOT,则返回0,过程如下:

    1. mysql> SELECT @@sql_mode\G;
    2. *************************** 1. row ***************************
    3. @@sql_mode:
    4. 1 row in set (0.00 sec)
    5. mysql> SELECT not 0 BETWEEN -1 AND 1\G;
    6. *************************** 1. row ***************************
    7. NOT 0 BETWEEN -1 AND 1: 0
    8. 1 row in set (0.00 sec)

但是如果启用HIGH_NOT_PRECEDENCE模式,则SELECT NOT 0 BETWEEN -1 AND 1被解释为SELECT(NOT 0)BETWEEN -1 AND 1,结果就完全相反,如下所示:

  1. mysql> SELECT NOT 0 BETWEEN -1 AND 1\G;
  2. *************************** 1. row ***************************
  3. NOT 0 BETWEEN -1 AND 1: 1
  4. 1 row in set (0.00 sec)

从上述例子中还能看出,在MySQL数据库中BETWEEN a AND b被解释为[a,b]。下面做两个简单的测试。

  1. mysql> SELECT 1 BETWEEN -1 AND 1\G;
  2. *************************** 1. row ***************************
  3. 1 BETWEEN -1 AND 1: 1
  4. 1 row in set (0.00 sec)
  5. mysql> SELECT -1 BETWEEN -1 AND 1\G;
  6. *************************** 1. row ***************************
  7. -1 BETWEEN -1 AND 1: 1
  8. 1 row in set (0.00 sec)

IGNORE_SPACE:函数名和括号“(”之间有空格。除了增加一些烦恼,这个选项好像没有任何好处,要访问保存为关键字的数据库、表或列名, 用户必须引用该选项。例如某个表中有user这一列,而MySQL数据库中又有user这个函数, user会被解释为函数,如果想要选择user这一列,则需要引用。

NO_AUTO_CREATE_USER:禁止GRANT创建密码为空的用户。

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

NO_BACKSLASH_ESCAPES:反斜杠“\”作为普通字符而非转义符,示例如下:

  1. mysql> SET sql_mode=‘‘;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> SELECT ‘\\‘\G;
  4. *************************** 1. row ***************************
  5. \: \
  6. 1 row in set (0.00 sec)
  7. mysql> SET sql_mode=‘NO_BACKSLASH_ESCAPES‘;
  8. Query OK, 0 rows affected (0.00 sec)
  9. mysql> SET ‘\\‘\G;
  10. *************************** 1. row ***************************
  11. \\: \\
  12. 1 row in set (0.00 sec)

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

NO_ENGINE_SUBSTITUTION:如果需要的存储引擎被禁用或未编译,那么抛出错误。默认用默认的存储引擎替代,并抛出一个异常。

NO_UNSIGNED_SUBTRACTION:之前已经介绍过,启用这个选项后两个UNSIGNED类型相减返回SIGNED类型。

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

NO_ZERO_IN_DATE:在严格模式下,不允许日期和月份为零。如“2011-00-01”和“2011-01-00”这样的格式是不允许的。采用日期或月份为零的格式时MySQL都会直接抛出错误而非警告,示例如下:

  1. mysql> SET sql_mode=‘NO_ZERO_IN_DATE‘;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> CREATE TABLE a ( a DATETIME );
  4. Query OK, 0 rows affected (0.04 sec)
  5. mysql> INSERT INTO a SELECT ‘2011-01-00‘;
  6. ERROR 1292 (22007): Incorrect datetime value: ‘2011-01-00‘ for column ‘a‘ at row 1

ONLY_FULL_GROUP_BY:对于GROUP BY聚合操作,如果在SELECT中的列没有在GROUP BY中出现,那么这句SQL是不合法的,因为a列不在GROUP BY从句中,示例如下:

  1. mysql> SET sql_mode=‘ONLY_FULL_GROUP_BY‘;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> SELECT a,SUM(b) FROM t GROUP BY b;
  4. ERROR 1055 (42000): ‘test.t.a‘ isn‘t in GROUP BY

PAD_CHAR_TO_FULL_LENGTH:对于CHAR类型字段,不要截断空洞数据。空洞数据就是自动填充值为0x20的数据。先来看MySQL数据库在默认情况下的表现。

  1. mysql> CREATE TABLE t ( a CHAR(10) );
  2. Query OK, 0 rows affected (0.04 sec)
  3. mysql> INSERT INTO t SELECT ‘a‘;
  4. Query OK, 1 row affected (0.01 sec)
  5. Records: 1  Duplicates: 0  Warnings: 0
  6. mysql>SELECT a,CHAR_LENGTH(a),HEX(a) FROM t\G;
  7. *************************** 1. row ***************************
  8. a: a
  9. CHAR_LENGTH(a): 1
  10. HEX(a): 61
  11. 1 row in set (0.04 sec)

可以看到,在默认情况下,虽然a列是CHAR类型,但是返回的长度是1,这是因为MySQL数据库已经对后面的空洞数据进行了截断。若启用PAD_CHAR_TO_FULL_LENGTH选项,则反映的是实际存储的内容,例如:

  1. mysql> SELECT a,CHAR_LENGTH(a),HEX(a) FROM t\G;
  2. *************************** 1. row ***************************
  3. a: a
  4. CHAR_LENGTH(a): 10
  5. HEX(a): 61202020202020202020
  6. 1 row in set (0.00 sec)

可以看到在CHAR列a中实际存储的值为0x61202020202020202020。

PIPES_AS_CONCAT:将“||”视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似,例如:

  1. mysql> SET sql_mode=‘pipes_as_concat‘;
  2. Query OK, 0 rows affected (0.01 sec)
  3. mysql> SELECT ‘a‘||‘b‘||‘c‘\G;
  4. *************************** 1. row ***************************
  5. ‘a‘||‘b‘||‘c‘: abc
  6. 1 row in set (0.00 sec)

REAL_AS_FLOAT:将REAL视为FLOAT的同义词,而不是DOUBLE的同义词。

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

在严格模式下,一旦任何操作的数据产生问题,都会终止当前的操作。对于启用STRICT_ALL_TABLES选项的非事务引擎来说,这时数据可能停留在一个未知的状态。这可能不是所有非事务引擎愿意看到的一种情况,因此需要非常小心这个选项可能带来的潜在影响。

下面的几种SQL_MODE设置是之前讨论的几种选项的组合。

ANSI:等同于REAL_AS_FLOAT、PIPES_AS_CONCAT和ANSI_QUOTES、IGNORE_SPACE的组合。

ORACLE:等同于PIPES_AS_CONCAT、 ANSI_QUOTES、IGNORE_SPACE、 NO_KEY_OPTIONS、 NO_TABLE_OPTIONS、 NO_FIELD_OPTIONS和NO_AUTO_CREATE_USER的组合。

TRADITIONAL:等同于STRICT_TRANS_TABLES、 STRICT_ALL_TABLES、NO_ZERO_IN_DATE、NO_ZERO_DATE、 ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER和 NO_ENGINE_SUBSTITUTION的组合。

MSSQL:等同于PIPES_AS_CONCAT、 ANSI_QUOTES、 IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS和 NO_FIELD_OPTIONS的组合。

DB2:等同于PIPES_AS_CONCAT、ANSI_QUOTES、 IGNORE_SPACE、NO_KEY_OPTIONS、 NO_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、 NO_TABLE_OPTIONS、 NO_FIELD_OPTIONS和 NO_AUTO_CREATE_USER的组合。

原文地址:http://book.51cto.com/art/201204/331329.htm

时间: 2024-08-02 19:51:36

SQL_MODE设置讲解的相关文章

MySQL数据类型:SQL_MODE设置不容忽视

[IT168 技术]SQL_MODE可能是比较容易让开发人员和DBA忽略的一个变量,默认为空.SQL_MODE的设置其实是比较冒险的一种设置,因为在这种设置下可以允许一些非法操作,比如可以将NULL插入NOT NULL的字段中,也可以插入一些非法日期,如“2012-12-32”.因此在生产环境中强烈建议开发人员将这个值设为严格模式,这样有些问题可以在数据库的设计和开发阶段就能发现,而如果在生产环境下运行数据库后发现这类问题,那么修改的代价将变得十分巨大.此外,正确地设置SQL_MODE还可以做一

vmwvare 网卡设置讲解

1.Bridged 桥接 会选择你电脑上的真实的网卡和你的计算机进行通信,设置成和你真实机同一网段的IP,就可以进行通信,并且可以和局域网内的其他用户进行通信. 2.NAT 使用已共享的IP地址 会使用 VMware Network Adapter VMnet8 3.Host-only  与主机共享一个私有网络 会使用 VMware Network Adapter VMnet1 和真实机通信,不能访问互联网 4.自定义 注意:要想和本机通信,要在真实机中设置 VMnet8 或者 VMnet1 I

MY SQL sql_mode设置

最近在MS SQL中添加MY SQL的链接服务器,通过openquery执行insert操作的时候,一直失败,错误信息如下: 后经多番查询,确定是目标服务器MY SQL的sql_mode设置的问题,修改如下设置即可正常插入. set sql_mode='NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' 不过最终还有点疑问,有的表主键字段在Select语句中,紧挨着Select关键字时,插入mysql表中主键的值为空,如果改变主键字段的位置,即可正常插入.原因

SQL_MODE设置

1.1.   SQL_MODE设置 在生产环境中强烈建议将这个值设置为严格模式,这样有些问题可以在数据库的设计和开发阶段就能实现,而如果在生产环境下运行数据库后发现这类问题,那么修改的代价将变得十分巨大.此外正确地设置sql_mode还可以做一些约束(constraint)检查的工作. 对于sql_mode的设置,可以在配置文件.客户端.当前会话或者全局会话中设置.查看sql_mode的设置情况: mysql>select @@global.sql_mode; +----------------

IntelliJ IDEA 常用设置讲解

说明 IntelliJ IDEA 有很多人性化的设置我们必须单独拿出来讲解,也因为这些人性化的设置让我们这些 IntelliJ IDEA 死忠粉更加死心塌地使用它和分享它. 常用设置 IntelliJ IDEA 的代码提示和补充功能有一个特性:区分大小写.如上图标注 1 所示,默认就是 First letter 区分大小写的. 区分大小写的情况是这样的:比如我们在 Java 代码文件中输入 stringBuffer IntelliJ IDEA 是不会帮我们提示或是代码补充的,但是如果我们输入 S

IntelliJ IDEA 常用设置讲解3

IntelliJ IDEA 有很多人性化的设置我们必须单独拿出来讲解,也因为这些人性化的设置让我们这些 IntelliJ IDEA 死忠粉更加死心塌地使用它和分享它. 常用设置 如上图 Gif 所示,当我们在编辑某个文件的时候,自动定位到当前文件所在的 Project 组件窗口位置. 如上图 Gif 所示,即使我们项目没有使用版本控制功能,IntelliJ IDEA 也给我们提供了本地文件历史记录.除了简单的记录之外,我们还可以给当前版本加标签. 如上图 Gif 所示,我们还可以根据选择的代码,

IntelliJ IDEA 常用设置讲解2

IntelliJ IDEA 有很多人性化的设置我们必须单独拿出来讲解,也因为这些人性化的设置让我们这些 IntelliJ IDEA 死忠粉更加死心塌地使用它和分享它. 常用设置 如上图 Gif 所示,当我们设置了组件窗口的 Pinned Mode 属性之后,在切换到其他组件窗口的时候,已设置该属性的窗口不会自动隐藏. 如上图 Gif 所示,我们可以通过 Alt + F1 + 1 快捷键来定位当前文件所在 Project 组件窗口中的位置. 如上图 Gif 所示,我们可以勾选此设置后,增加 Ctr

IntelliJ IDEA 常用设置讲解1

IntelliJ IDEA 有很多人性化的设置我们必须单独拿出来讲解,也因为这些人性化的设置让我们这些 IntelliJ IDEA 死忠粉更加死心塌地使用它和分享它. 常用设置 IntelliJ IDEA 的代码提示和补充功能有一个特性:区分大小写.如上图标注 1 所示,默认就是 First letter 区分大小写的. 区分大小写的情况是这样的:比如我们在 Java 代码文件中输入 stringBuffer IntelliJ IDEA 是不会帮我们提示或是代码补充的,但是如果我们输入 Stri

MySQL sql_mode设置

在MySQL5.7版本中创建表 CREATE TABLE `investor_seat` ( `id` int(11) NOT NULL AUTO_INCREMENT , `investorId` int(11) NOT NULL COMMENT '投资人id', `seatId` int(11) NOT NULL COMMENT '席位id', `maybe` float NOT NULL COMMENT '席位归属某帮派或者某人的概率', `investorName` varchar(28)