MySQL sql_mode 详解

本文详细介绍了MySQL中的SQL_MODE设置及其作用。包括如何设置全局及会话级别的SQL_MODE,各种模式的具体含义,例如严格模式、日期检查等。同时,还探讨了不同模式对数据插入和查询的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.itpub.net/29773961/viewspace-1813501/

SQL_MODE:通过对其正确的设置可以完成一些约束检查的工作,设置时,可在配置文件my.cnf或my.ini中进行,也可在客户端中进行,并可分别进行全局的设置或当前会话的设置。


查看SQL_MODE设置情况:
  1. mysql> SHOW VARIABLES LIKE 'SQL_MODE';
  2. +---------------+--------------------------------------------+
  3. | Variable_name | Value                                      |
  4. +---------------+--------------------------------------------+
  5. | sql_mode      | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
  6. +---------------+--------------------------------------------+
  7. 1 row in set (0.00 sec)

  8. mysql> SELECT @@global.SQL_MODE;
  9. +--------------------------------------------+
  10. | @@global.SQL_MODE                          |
  11. +--------------------------------------------+
  12. | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
  13. +--------------------------------------------+
  14. 1 row in set (0.00 sec)

  15. mysql> SELECT @@session.SQL_MODE;
  16. +--------------------------------------------+
  17. | @@session.SQL_MODE                         |
  18. +--------------------------------------------+
  19. | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
  20. +--------------------------------------------+
  21. 1 row in set (0.00 sec)


在client设置方法很简单:
  1. mysql> SET global sql_mode='STRICT_TRANS_TABLES';
  2. Query OK, 0 rows affected (0.00 sec)
这样可以将sql_mode设置为“严格模式”。

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


其他可以设置的选项有:

STRICT_TRANS_TALES(严格模式):
只对支持事务的表启用严格模式

STRICT_ALL_TABLES(严格模式):
对所有引擎的表都启用严格模式

严格模式:
在此模式下,一旦任何操作的数据产生问题,都将终止当前的操作,对于启用 STRICT_ALL_TABLE S 的非事务引擎而言,这时数据可能停留在一个未知的状态,因此需非常小心这个选项可能带来的潜在影响。

ALLOW_INVALID_DATES:
不完全对日期合法性作检查,只检查月份是否在1~12,日期是否在1~31之间;仅对DATE和DATETIME有效,而对TIMESTAMP无效,因为TIMESTAMP总要求一个合法的输入。

ANSI_QUOTES:
启用后,不能用双引号来引用字符串,因为"(双引号)将被解释为标识符
  1. mysql> CREATE TABLE a ( a char(5));
  2. Query OK, 0 rows affected (0.26 sec)

  3. mysql> INSERT INTO a SELECT 'abc';
  4. Query OK, 1 row affected (0.05 sec)
  5. Records: 1 Duplicates: 0 Warnings: 0

  6. mysql> SET SQL_MODE='ANSI_QUOTES';
  7. Query OK, 0 rows affected (0.00 sec)

  8. mysql> INSERT INTO a SELECT "abc";
  9. ERROR 1054 (42S22): Unknown column 'abc' in 'field list'

  10. mysql> SELECT @@session.sql_mode;
  11. +--------------------+
  12. | @@session.sql_mode |
  13. +--------------------+
  14. | ANSI_QUOTES        |
  15. +--------------------+
  16. 1 row in set (0.00 sec)

ERROR_FOR_DIVISION_BY_ZERO:
启用后,在insert或update过程中,若数据被零除(或MOD(x,0),则产生错误,若未启用,则产生警告,数据被零除时系统返回NULL。

HIGH_NOT_PRECEDENCE:
启用后,可获得以前旧版本的优先级:
NOT a BETWEEN b AND c 这个语句:
now: NOT (a BETWEEN b AND c)
before: (NOT a) BETWEEN b AND c

IGNORE_SPACE:
启用后,忽略函数名和括号"("之间空格,要访问保存为关键字的数据库名,表名,列名时,需启用。
  1. mysql> SELECT NOW ();
  2. ERROR 1630 (42000): FUNCTION test.NOW does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual
  3. mysql> SET SQL_MODE='IGNORE_SPACE';
  4. Query OK, 0 rows affected (0.00 sec)

  5. mysql> SELECT NOW ();
  6. +---------------------+
  7. | NOW ()              |
  8. +---------------------+
  9. | 2015-10-08 17:49:35 |
  10. +---------------------+
  11. 1 row in set (0.00 sec)

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

NO_AUTO_VALUE_ON_ZERO:
在自增长的列中插入0或NULL将不会是下一个自增长值。

NO_BACKSLASH_ESCAPES:
反斜杠"\"作为普通字符而非转义字符
  1. mysql> SET SQL_MODE='';
  2. Query OK, 0 rows affected (0.00 sec)

  3. mysql> SELECT '\\';
  4. +---+
  5. | \ |
  6. +---+
  7. | \ |
  8. +---+
  9. 1 row in set (0.00 sec)

  10. mysql> SET SQL_MODE='NO_BACKSLASH_ESCAPES';
  11. Query OK, 0 rows affected (0.00 sec)

  12. mysql> SELECT '\\';
  13. +----+
  14. | \\ |
  15. +----+
  16. | \\ |
  17. +----+
  18. 1 row in set (0.00 sec)

NO_DIR_IN_CREATE:
在创建表时忽略所有index directory和data directory的选项。

NO_ENGINE_SUBSTITUTION:
启用后,若需要的存储引擎被禁用或未编译,则抛出错误;未启用时将用默认的存储引擎代替,并抛出一个异常。

NO_UNSIGNED_SUBSTRACTION:
启用后,两个UNSIGNED类型相减返回SIGNED类型。

NO_ZERO_DATE:
启用后,不允许插入“0000-00-00 00:00:00”形如此类的零日期,这将抛出一个错误,若未启用,则可插入但仅会抛出一个警告。

NO_ZERO_IN_DATE:
启用后,不允许月份和日期为零,和NO_ZERO_DATE一起启用,如“1999-01-00”将抛出错误而非警告。
若单独启用本项,则会抛出warning,然后插入如“0000-00-00 00:00:00”。

ONLY_FULL_GROUP_BY:
对于GROUP BY聚合操作,若select中的列没有在group by中出现,那么这句SQL是不合法的。

PAD_CHAR_TO_FULL_LENGTH:
启用后,对于CHAR类型将不会截断空洞数据;
  1. mysql> CREATE TABLE a ( a char(10), b varchar(10));
  2. Query OK, 0 rows affected (0.29 sec)

  3. mysql> INSERT INTO a SELECT 'a','b';
  4. Query OK, 1 row affected (0.03 sec)
  5. Records: 1 Duplicates: 0 Warnings: 0;

  6. mysql> SELECT CHAR_LENGTH(a), CHAR_LENGTH(b) FROM a;
  7. +----------------+----------------+
  8. | CHAR_LENGTH(a)  | CHAR_LENGTH(b |
  9. +----------------+----------------+
  10. | 1              | 1              |
  11. +----------------+----------------+
  12. 1 row in set (0.01 sec)

  13. mysql> SET SQL_MODE='PAD_CHAR_TO_FULL_LENGTH';
  14. Query OK, 0 rows affected (0.00 sec)

  15. mysql> SELECT CHAR_LENGTH(a), CHAR_LENGTH(b) FROM a;
  16. +----------------+----------------+
  17. | CHAR_LENGTH(a) | CHAR_LENGTH(b) |
  18. +----------------+----------------+
  19. | 10             | 1              |
  20. +----------------+----------------+
  21. 1 row in set (0.00 sec)

PIPES_AS_CONCAT:
将"||"视为连接操作符而非“或运算符”。

REAL_AS_FLOAT:
将REAL视为FLOAT的同义词而非DOUBLE的同义词。


组合选项:
·ANSI:
REAL_AS_FLOAT、PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、ANSI
·ORACLE:
PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS、NO_AUTO_CREATE_USER、ORACLE
·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、TRADITIONAL
·MSSQL:
PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、MSSQL、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS、MSSQL
·DB2:
PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS、 DB2
·MYSQL323:
HIGH_NOT_PRECEDENCE、MYSQL323
·MYSQL40:
HIGH_NOT_PRECEDENCE、 MYSQL40
·MAXDB:
PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS、NO_AUTO_CREATE_USER、
MAXDB




参考文档:
MySQL 5.6 Reference Manual
姜承尧《MySQL技术内幕:SQL编程》
<think>嗯,用户给了这两条SQL语句,是关于设置sql_mode的。首先,我需要理解sql_mode的作用。记得sql_modeMySQL中用来控制服务器行为的参数,不同的模式会影响语法检查、数据校验等。用户可能想了解这两条命令的具体作用,或者他们遇到了什么问题需要设置这些模式。 先看第一条:SET sql_mode = ...。这应该是设置当前会话的sql_mode,只影响当前的连接。而第二条是SET @@global.sql_mode,这是全局设置,会影响之后所有的新连接。但可能需要SUPER权限,用户是否有权限执行这个呢?可能需要提醒用户注意权限问题。 然后看具体的模式选项。STRICT_TRANS_TABLES,严格模式,对于事务型存储引擎,比如InnoDB,会严格校验数据,比如插入的数据不符合字段类型会报错而不是警告。而如果是非事务型的,可能还是会调整行为。 NO_ZERO_IN_DATE和NO_ZERO_DATE,这两个应该是不允许日期中的零值,比如'0000-00-00'这样的日期会被视为无效。ERROR_FOR_DIVISION_BY_ZERO,除零错误,这样在除零时会报错而不是返回NULL。NO_ENGINE_SUBSTITUTION,当指定的存储引擎不可用时,阻止自动替换成默认引擎,而是报错。 用户可能是在配置MySQL服务器,确保数据的严格校验,避免无效的数据插入,或者在迁移数据库时需要保持一致性。也可能他们在之前遇到了问题,比如日期中有零值,或者除零错误被忽略,现在想加强约束。 需要解释每个选项的作用,以及设置全局和会话级别的影响。还要提醒用户,修改全局变量后需要重启或者让其他会话重新连接才能生效。另外,永久生效可能需要修改配置文件,比如my.cnf,否则重启后设置会丢失。 可能用户的问题背景是他们在部署应用时,数据库出现了数据校验的问题,或者迁移数据时遇到了严格模式的限制。需要给出实际应用的例子,比如插入无效日期时的不同行为,或者除零错误导致的问题。 还要注意语法是否正确,比如是否每个模式选项都正确拼写,逗号分隔,没有多余的空格。用户给出的语句看起来是正确的,但可能需要确认MySQL版本是否支持这些选项,因为不同版本可能有变化,比如在MySQL 5.7和8.0中某些模式的行为是否有调整。 总结一下,回答的结构应该是先解释每个命令的作用(会话和全局),然后详细说明每个模式选项的含义和影响,最后给出使用场景和注意事项,比如权限、持久化配置等。这样用户能全面理解这两条语句的作用,以及如何正确应用在他们的环境中。</think>以下是对这两条 SQL 语句的逐步解释: --- ### **1. 语句作用** 这两条命令用于配置 MySQL 的 `sql_mode`,控制数据库对数据校验和操作的严格程度,目的是: - 禁止不安全或模糊的数据操作 - 启用严格的语法校验 - 防止意外数据丢失或错误 --- ### **2. 作用范围区别** - **`SET sql_mode = ...`** 仅修改 **当前会话** 的配置(当前数据库连接有效,断开后失效)。 - **`SET @@global.sql_mode = ...`** 修改 **全局配置**(影响所有新建立的会话),但需注意: - 需要 `SUPER` 权限 - 重启 MySQL 服务后失效(如需永久生效需修改配置文件 `my.cnf`) --- ### **3. 各模式参数详解** | 参数名称 | 作用 | |---------|------| | **`STRICT_TRANS_TABLES`** | 对事务型存储引擎(如 InnoDB)启用严格模式:<br> - 数据不符合定义时(如超出字段长度)**直接报错**,而非警告或自动截断 | | **`NO_ZERO_IN_DATE`** | 禁止 `0000-00-00` 这种 **零值日期**(但允许 `2000-00-01` 这类部分零值)| | **`NO_ZERO_DATE`** | 完全禁止 `0000-00-00` 日期 | | **`ERROR_FOR_DIVISION_BY_ZERO`** | 除零操作时 **报错**(默认返回 `NULL` 并警告)| | **`NO_ENGINE_SUBSTITUTION`** | 指定存储引擎不可用时 **报错**(默认会自动替换为默认引擎)| --- ### **4. 典型使用场景** - **数据迁移**:确保目标库严格校验数据合法性 - **开发环境**:强制开发者遵循严谨的数据规范 - **防止逻辑漏洞**:避免隐式数据截断或除零错误导致业务异常 --- ### **5. 注意事项** 1. **权限要求**:修改全局模式需 `SUPER` 权限 2. **持久化配置**:如需永久生效,需在 `my.cnf` 中添加: ```ini [mysqld] sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION ``` 3. **版本兼容性**:MySQL 5.7+ 默认包含部分严格模式,建议通过 `SELECT @@sql_mode;` 确认当前配置 --- ### **示例验证** ```sql -- 尝试插入非法日期(启用严格模式后会报错) INSERT INTO table (date_column) VALUES ('2023-00-10'); -- 错误: [HY000][1292] Incorrect date value: '2023-00-10' ``` 通过此配置,可显著提升数据完整性和操作安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值