MySQL服务器可以在不同的SQL模式下运行,并且可以根据sql_mode
系统变量的值对不同的客户端应用不同的模式。DBA可以设置全局SQL模式以匹配站点服务器操作需求,并且每个应用程序可以将其会话SQL模式设置为自己的需求。
模式会影响MySQL支持的SQL语法以及数据验证检查的效果。这使得在不同的环境中使用MySQL变得更容易,并且可以将MySQL与其他数据库服务器一起使用。
有关MySQL中服务器SQL模式常见问题的答案,请参见第A.3节“MySQL 5.7 FAQ:服务器SQL模式”。
使用InnoDB
表格时,还要考虑innodb_strict_mode
系统变量。它启用对InnoDB
表格的额外错误检查 。
设置SQL模式
在MySQL 5.7的默认SQL模式包括以下模式:ONLY_FULL_GROUP_BY
, STRICT_TRANS_TABLES
, NO_ZERO_IN_DATE
,NO_ZERO_DATE
, ERROR_FOR_DIVISION_BY_ZERO
, NO_AUTO_CREATE_USER
,和 NO_ENGINE_SUBSTITUTION
。
在ONLY_FULL_GROUP_BY
和 STRICT_TRANS_TABLES
模式在MySQL 5.7.5添加。该 NO_AUTO_CREATE_USER
模式已添加到MySQL 5.7.7。这些 ERROR_FOR_DIVISION_BY_ZERO
, NO_ZERO_DATE
和 NO_ZERO_IN_DATE
模式被添加到MySQL 5.7.8。有关对默认SQL模式值的这些更改的更多讨论,请参阅 MySQL 5.7中的SQL模式更改。
要在服务器启动时设置SQL模式,请使用 命令行 上的选项或 (Unix操作系统)或(Windows)等选项文件。 是用逗号分隔的不同模式的列表。要明确清除SQL模式,请使用命令行或选项文件将其设置为空字符串 。 --sql-mode="
modes
"sql-mode="
modes
"my.cnf
my.ini
modes
--sql-mode=""
sql-mode=""
MySQL安装程序可能会在安装过程中配置SQL模式。例如, mysql_install_db将创建一个my.cnf
在基本安装目录中命名的默认选项文件。该文件包含设置SQL模式的行; 请参见第4.4.2节“ mysql_install_db- 初始化MySQL数据目录”。
如果SQL模式与默认或预期不同,请检查服务器在启动时读取的选项文件中的设置。
要在运行时更改SQL模式,请sql_mode
使用以下SET
语句设置全局或会话 系统变量:
SET GLOBAL sql_mode = 'modes'; SET SESSION sql_mode = 'modes';
设置GLOBAL
变量需要 SUPER
特权,并影响从此时开始连接的所有客户端的操作。设置SESSION
变量只影响当前的客户端。每个客户可以随时更改其会话 sql_mode
值。
要确定当前的全局或会话 sql_mode
值,请使用以下语句:
SELECT @@GLOBAL.sql_mode;
SELECT @@SESSION.sql_mode;
SQL模式和用户定义的分区。 创建数据并将其插入分区表后,更改服务器SQL模式可能会导致此类表的行为发生重大变化,并可能导致数据丢失或损坏。强烈建议您一旦创建了使用用户定义分区的表格,就不要更改SQL模式。
在复制分区表时,主站和从站上不同的SQL模式也会导致问题。为了获得最佳结果,您应始终在主服务器和从服务器上使用相同的服务器SQL模式。
有关更多信息,请参见第22.6节“分区的限制和限制”。
最重要的SQL模式
最重要的sql_mode
价值可能是这些:
-
此模式更改语法和行为以更加符合标准SQL。这是 本节最后列出的特殊 组合模式之一。
-
如果某个值无法插入到事务表中,请中止该语句。对于非事务性表,如果该值出现在单行语句或多行语句的第一行中,则中止该语句。更多细节在本节后面给出。
从MySQL 5.7.5开始,默认的SQL模式包括
STRICT_TRANS_TABLES
。 -
使MySQL像“ 传统 ”的 SQL数据库系统一样行事。在将不正确的值插入列时,此模式的简单描述是 “ 给出错误而不是警告 ”。这是本节最后列出的特殊组合模式之一。
当本手册提到“ 严格模式 ”时,它表示具有一个或两个STRICT_TRANS_TABLES
或 STRICT_ALL_TABLES
启用的模式 。
SQL模式的完整列表
以下列表介绍了所有支持的SQL模式:
-
不要执行完整的日期检查。只检查月份是在1到12之间,日期是在1到31之间。这对于在三个不同领域获得年份,月份和日期的Web应用程序非常方便,并且您想要存储究竟是用户插入(没有日期验证)。此模式适用于
DATE
和DATETIME
列。它不适用TIMESTAMP
列,这总是需要一个有效的日期。服务器要求月份和日期值是合法的,而不是分别在1到12和1到31的范围内。禁用严格模式后,会生成
'2004-04-31'
转换为 无效日期'0000-00-00'
和警告。启用严格模式后,无效的日期会生成错误。要允许这样的日期,请启用ALLOW_INVALID_DATES
。 -
治疗
"
作为标识符引号字符(如`
引号字符),而不是作为一个字符串引号字符。您仍然可以使用`
引用启用此模式的标识符。与ANSI_QUOTES
启用,则不能使用双引号引用文字字符串,因为它被解释为标识符。 -
该
ERROR_FOR_DIVISION_BY_ZERO
模式影响零除的处理,其中包括 。对于数据更改操作(, ),其效果也取决于严格SQL模式是否启用。MOD(
N
,0)INSERT
UPDATE
-
如果这个模式没有被启用,除以零插入
NULL
并且不产生警告。 -
如果启用此模式,则除以零插入
NULL
并产生警告。 -
如果这个模式和严格的模式被启用,除以零产生一个错误,除非
IGNORE
给出。对于INSERT IGNORE
和UPDATE IGNORE
,除以零插入NULL
并产生一个警告。
因为
SELECT
,除以零回报NULL
。ERROR_FOR_DIVISION_BY_ZERO
无论是否启用严格模式,启用 都会导致产生警告。从MySQL 5.7.4开始,
ERROR_FOR_DIVISION_BY_ZERO
已被弃用。在MySQL 5.7.4到5.7.7中,ERROR_FOR_DIVISION_BY_ZERO
当明确命名时什么都不做。相反,其效果包含在严格SQL模式的效果中。在MySQL 5.7.8及更高版本中,ERROR_FOR_DIVISION_BY_ZERO
如果明确命名,并且不是严格模式的一部分,就像在MySQL 5.7.4之前一样。但是,它应该与严格模式一起使用,并且默认情况下处于启用状态。如果ERROR_FOR_DIVISION_BY_ZERO
在未启用严格模式的情况下启用警告, 反之亦然。有关其他讨论,请参阅 MySQL 5.7中的SQL模式更改。由于
ERROR_FOR_DIVISION_BY_ZERO
已被弃用,它将在未来的MySQL版本中作为单独的模式名称被删除,其效果包含在严格SQL模式的影响中。 -
-
NOT
运算符 的优先级是这样的表达式,如NOT a BETWEEN b AND c
解析为NOT (a BETWEEN b AND c)
。在一些旧版本的MySQL中,表达式被解析为(NOT a) BETWEEN b AND c
。旧的高优先级行为可以通过启用HIGH_NOT_PRECEDENCE
SQL模式来获得 。mysql> SET sql_mode = ''; mysql> SELECT NOT 1 BETWEEN -5 AND 5; -> 0 mysql> SET sql_mode = 'HIGH_NOT_PRECEDENCE'; mysql> SELECT NOT 1 BETWEEN -5 AND 5; -> 1
-
允许函数名称和
(
字符之间的空格 。这导致内置函数名称被视为保留字。因此,必须按照第9.2节“模式对象名称”中的描述引用与函数名称相同的标识符。例如,因为有一个COUNT()
函数,count
在下面的语句中使用 作为表名称会导致一个错误:mysql> CREATE TABLE count (i INT); ERROR 1064 (42000): You have an error in your SQL syntax
表名应该引用:
mysql> CREATE TABLE `count` (i INT); Query OK, 0 rows affected (0.00 sec)
在
IGNORE_SPACE
SQL模式适用于内置函数,而不是用户定义的函数或存储功能。无论是否IGNORE_SPACE
启用,总是允许在UDF或存储的函数名称后面有空格 。有关进一步讨论
IGNORE_SPACE
,请参见 第9.2.4节“函数名称分析和解析”。 -
防止
GRANT
声明自动创建新的用户帐户,除非认证信息被指定。该语句必须使用IDENTIFIED BY
或使用身份验证插件指定非空密码IDENTIFIED WITH
。最好是创建MySQL帐户
CREATE USER
而不是GRANT
。NO_AUTO_CREATE_USER
已弃用,默认的SQL模式包括NO_AUTO_CREATE_USER
。分配给sql_mode
该改变NO_AUTO_CREATE_USER
模式状态产生警告,除了设置分配sql_mode
到DEFAULT
。NO_AUTO_CREATE_USER
将在未来的MySQL版本中被删除,此时其效果将始终启用(GRANT
不会创建帐户)。以前,
NO_AUTO_CREATE_USER
弃用之前 ,不能启用它的一个原因是它不是复制安全的。现在,它可以启用和进行复制,安全的用户管理CREATE USER IF NOT EXISTS
,DROP USER IF EXISTS
和ALTER USER IF EXISTS
而不是GRANT
。当从属服务器与主服务器上的授权不同时,这些语句可以实现安全复制。请参见第13.7.1.2节“CREATE USER语法”, 第13.7.1.3节“DROP USER语法”和 第13.7.1.1节“ALTER USER语法”。 -
NO_AUTO_VALUE_ON_ZERO
影响AUTO_INCREMENT
列的处理。通常情况下,通过插入NULL
或 插入,为列生成下一个序列号0
。NO_AUTO_VALUE_ON_ZERO
为了0
只NULL
产生下一个序列号就抑制了这种行为。如果
0
已经存储在表格的AUTO_INCREMENT
列中,此模式可能很有用。(0
顺便说一句,存储不是推荐的做法。)例如,如果您使用mysqldump转储表,然后重新加载它,MySQL通常会在遇到0
值时生成新的序列号,从而导致与内容不同的表被甩了NO_AUTO_VALUE_ON_ZERO
重新加载转储文件之前启用 解决此问题。 mysqldump现在会自动在其输出中包含一个使能的语句NO_AUTO_VALUE_ON_ZERO
,以避免这个问题。 -
禁止
\
在字符串中使用反斜杠字符()作为转义字符。启用此模式后,反斜杠将变成普通字符一样。 -
创建表格时,忽略所有
INDEX DIRECTORY
和DATA DIRECTORY
指令。该选项在从属复制服务器上很有用。 -
控制默认存储引擎的自动替换,例如
CREATE TABLE
或者ALTER TABLE
指定了禁用或未编译的存储引擎。默认的SQL模式包括
NO_ENGINE_SUBSTITUTION
。因为存储引擎在运行时可以被插入,所以不可用的引擎被以同样的方式处理:
在
NO_ENGINE_SUBSTITUTION
禁用CREATE TABLE
的情况下,使用默认引擎,如果所需引擎不可用,则会发生警告。因为ALTER TABLE
,发生警告,表格没有被改变。与
NO_ENGINE_SUBSTITUTION
启用,则会出现错误,并且不会创建或修改的表,如果所需的引擎不可用。 -
不要在输出中打印MySQL特定的列选项
SHOW CREATE TABLE
。这种模式在可移植性模式下被mysqldump使用。 -
不要在输出中打印MySQL特定的索引选项
SHOW CREATE TABLE
。这种模式在可移植性模式下被mysqldump使用。 -
不要
ENGINE
在输出中打印MySQL特定的表选项(如 )SHOW CREATE TABLE
。这种模式在可移植性模式下被mysqldump使用。 -
整数值之间的减法,其中一个是类型的
UNSIGNED
,默认情况下会生成一个无符号的结果。如果结果否则会导致错误:mysql> SET sql_mode = ''; Query OK, 0 rows affected (0.00 sec) mysql> SELECT CAST(0 AS UNSIGNED) - 1; ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(cast(0 as unsigned) - 1)'
如果
NO_UNSIGNED_SUBTRACTION
启用了 SQL模式,结果是否定的:mysql> SET sql_mode = 'NO_UNSIGNED_SUBTRACTION'; mysql> SELECT CAST(0 AS UNSIGNED) - 1; +-------------------------+ | CAST(0 AS UNSIGNED) - 1 | +-------------------------+ | -1 | +-------------------------+
如果此操作的结果用于更新
UNSIGNED
整数列,则结果将被剪裁为列类型的最大值,如果NO_UNSIGNED_SUBTRACTION
启用,则剪切为0 。如果启用严格的SQL模式,则会发生错误,并且列保持不变。当
NO_UNSIGNED_SUBTRACTION
使能时,即使有任何操作数是无符号的,减法结果也是有符号的。例如,比较列的类型c2
在表t1
与该列的c2
表t2
:mysql> SET sql_mode=''; mysql> CREATE TABLE test (c1 BIGINT UNSIGNED NOT NULL); mysql> CREATE TABLE t1 SELECT c1 - 1 AS c2 FROM test; mysql> DESCRIBE t1; +-------+---------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------------------+------+-----+---------+-------+ | c2 | bigint(21) unsigned | NO | | 0 | | +-------+---------------------+------+-----+---------+-------+ mysql> SET sql_mode='NO_UNSIGNED_SUBTRACTION'; mysql> CREATE TABLE t2