MySQL 服务器可以在不同的 SQL 模式下运行,并且可以根据 sql_mode
系统变量的值,对不同的客户端应用不同的模式。DBA 可以设置全局 SQL 模式以匹配站点服务器操作要求,并且每个应用程序可以将其会话 SQL 模式设置为其自身的要求。
模式会影响 MySQL 支持的 SQL 语法以及它执行的数据验证检查。这使得在不同环境中使用 MySQL 以及将 MySQL 与其他数据库服务器一起使用变得更加容易。
有关 MySQL 中服务器 SQL 模式的常见问题的答案,请参见 第 A.3 节,“MySQL 8.4 常见问题解答:服务器 SQL 模式”。
使用 InnoDB
表时,还要考虑 innodb_strict_mode
系统变量。它为 InnoDB
表启用了额外的错误检查。
MySQL 8.4 中的默认 SQL 模式包括以下模式:ONLY_FULL_GROUP_BY
、STRICT_TRANS_TABLES
、NO_ZERO_IN_DATE
、NO_ZERO_DATE
、ERROR_FOR_DIVISION_BY_ZERO
和 NO_ENGINE_SUBSTITUTION
。
要在服务器启动时设置 SQL 模式,请在命令行上使用 --sql-mode="
选项,或者在选项文件(例如 modes
"my.cnf
(Unix 操作系统)或 my.ini
(Windows))中使用 sql-mode="
。 modes
"modes
是以逗号分隔的不同模式的列表。要显式清除 SQL 模式,请在命令行上使用 --sql-mode=""
或在选项文件中使用 sql-mode=""
将其设置为空字符串。
MySQL 安装程序可以在安装过程中配置 SQL 模式。
如果 SQL 模式与默认值或您的预期不同,请检查服务器在启动时读取的选项文件中的设置。
要在运行时更改 SQL 模式,请使用 SET
语句设置全局或会话 sql_mode
系统变量
SET GLOBAL sql_mode = 'modes';
SET SESSION sql_mode = 'modes';
设置 GLOBAL
变量需要 SYSTEM_VARIABLES_ADMIN
权限(或已弃用的 SUPER
权限),并且会影响从那时起连接的所有客户端的操作。设置 SESSION
变量只会影响当前客户端。每个客户端都可以随时更改其会话 sql_mode
值。
要确定当前全局或会话 sql_mode
设置,请选择其值
SELECT @@GLOBAL.sql_mode;
SELECT @@SESSION.sql_mode;
SQL 模式和用户定义的分区。 在创建分区表并将数据插入分区表后更改服务器 SQL 模式可能会导致此类表的行為发生重大变化,并可能导致数据丢失或损坏。强烈建议您一旦创建了采用用户定义分区的表,就永远不要更改 SQL 模式。
复制分区表时,源和副本上的 SQL 模式不同也可能导致问题。为了获得最佳结果,您应该始终在源和副本上使用相同的服务器 SQL 模式。
有关更多信息,请参见 第 26.6 节,“分区的限制”。
最重要的 sql_mode
值可能是以下这些
此模式会更改语法和行为,使其更符合标准 SQL。它是本节末尾列出的特殊 组合模式 之一。
如果一个值不能按原样插入到事务性表中,则中止该语句。对于非事务性表,如果该值出现在单行语句或多行语句的第一行中,则中止该语句。本节稍后将对此进行详细介绍。
使 MySQL 表现得像“传统”SQL 数据库系统。对这种模式的简单描述是,在将不正确的值插入列时“给出错误而不是警告”。它是本节末尾列出的特殊组合模式之一。
注意启用
TRADITIONAL
模式后,INSERT
或UPDATE
会在发生错误时立即中止。如果您使用的是非事务性存储引擎,这可能不是您想要的,因为在错误发生之前所做的数据更改可能不会回滚,从而导致更新“部分完成”。
当本手册提到“严格模式”时,它指的是启用了STRICT_TRANS_TABLES
或 STRICT_ALL_TABLES
中的一种或两种模式。
以下列表描述了所有受支持的 SQL 模式
不执行日期的完整检查。仅检查月份是否在 1 到 12 的范围内,日期是否在 1 到 31 的范围内。这对于在三个不同字段中获取年、月和日的 Web 应用程序很有用,并且可以完全存储用户插入的内容,而无需进行日期验证。此模式适用于
DATE
和DATETIME
列。它不适用于始终需要有效日期的TIMESTAMP
列。如果禁用
ALLOW_INVALID_DATES
,则服务器要求月份和日期值合法,而不仅仅是在 1 到 12 和 1 到 31 的范围内。如果禁用严格模式,则无效日期(例如'2004-04-31'
)将转换为'0000-00-00'
并生成警告。如果启用严格模式,则无效日期会生成错误。要允许此类日期,请启用ALLOW_INVALID_DATES
。将
"
视为标识符引号字符(类似于`
引号字符),而不是字符串引号字符。启用此模式后,您仍然可以使用`
为标识符加引号。启用ANSI_QUOTES
后,您不能使用双引号为文字字符串加引号,因为它们会被解释为标识符。ERROR_FOR_DIVISION_BY_ZERO
模式会影响除以零的处理方式,其中包括MOD(
。对于数据更改操作(N
,0)INSERT
、UPDATE
),其影响还取决于是否启用了严格 SQL 模式。如果未启用此模式,则除以零将插入
NULL
并且不会产生警告。如果启用此模式,则除以零将插入
NULL
并产生警告。如果同时启用了此模式和严格模式,则除以零会产生错误,除非还给出了
IGNORE
。对于INSERT IGNORE
和UPDATE IGNORE
,除以零将插入NULL
并产生警告。
对于
SELECT
,除以零返回NULL
。启用ERROR_FOR_DIVISION_BY_ZERO
还会产生警告,而不管是否启用了严格模式。ERROR_FOR_DIVISION_BY_ZERO
已弃用。ERROR_FOR_DIVISION_BY_ZERO
不是严格模式的一部分,但应与严格模式结合使用,并且默认情况下处于启用状态。如果启用ERROR_FOR_DIVISION_BY_ZERO
但未启用严格模式,反之亦然,则会发出警告。因为
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
允许函数名称和
(
字符之间存在空格。这会导致内置函数名称被视为保留字。因此,与函数名称相同的标识符必须像 第 11.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
,始终允许在可加载函数或存储函数名称后加空格。有关
IGNORE_SPACE
的进一步讨论,请参见 第 11.2.5 节“函数名称解析和解决方案”。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
的语句。启用此模式将禁用反斜杠字符 (
\
) 在字符串和标识符中用作转义字符。启用此模式后,反斜杠将成为与任何其他字符一样的普通字符,并且LIKE
表达式的默认转义序列将更改为不使用转义字符。创建表时,忽略所有
INDEX DIRECTORY
和DATA DIRECTORY
指令。此选项在副本服务器上很有用。当诸如
CREATE TABLE
或ALTER TABLE
之类的语句指定了已禁用或未编译的存储引擎时,控制默认存储引擎的自动替换。默认情况下,
NO_ENGINE_SUBSTITUTION
处于启用状态。因为存储引擎可以在运行时可插拔,所以不可用的引擎的处理方式相同
如果禁用
NO_ENGINE_SUBSTITUTION
,则对于CREATE TABLE
,将使用默认引擎,并且如果所需的引擎不可用,则会发出警告。对于ALTER TABLE
,会发出警告,并且不会更改表。如果启用
NO_ENGINE_SUBSTITUTION
,则如果所需的引擎不可用,则会发生错误,并且不会创建或更改表。默认情况下,整数值之间的减法(其中一个值为
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
后,减法结果将带符号,即使任何操作数都是无符号的。例如,将表t1
中的列c2
的类型与表t2
中的列c2
的类型进行比较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 SELECT c1 - 1 AS c2 FROM test; mysql> DESCRIBE t2; +-------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------------+------+-----+---------+-------+ | c2 | bigint(21) | NO | | 0 | | +-------+------------+------+-----+---------+-------+
这意味着
BIGINT UNSIGNED
在所有上下文中都不能 100% 使用。请参见 第 14.10 节“强制转换函数和运算符”。NO_ZERO_DATE
模式会影响服务器是否允许将'0000-00-00'
作为有效日期。其效果还取决于是否启用了严格 SQL 模式。如果未启用此模式,则允许使用
'0000-00-00'
,并且插入操作不会产生警告。如果启用了此模式,则允许使用
'0000-00-00'
,但插入操作会产生警告。如果启用了此模式和严格模式,则不允许使用
'0000-00-00'
,并且插入操作会产生错误,除非还指定了IGNORE
。对于INSERT IGNORE
和UPDATE IGNORE
,则允许使用'0000-00-00'
,但插入操作会产生警告。
NO_ZERO_DATE
已弃用。NO_ZERO_DATE
不是严格模式的一部分,但应与严格模式结合使用,并且默认情况下启用。如果在未启用严格模式的情况下启用了NO_ZERO_DATE
,反之亦然,则会发出警告。因为
NO_ZERO_DATE
已弃用,所以您应该预计它会在未来的 MySQL 版本中作为单独的模式名称被移除,其效果将包含在严格 SQL 模式的效果中。NO_ZERO_IN_DATE
模式会影响服务器是否允许年份部分不为零但月份或日期部分为 0 的日期。(此模式会影响'2010-00-01'
或'2010-01-00'
等日期,但不会影响'0000-00-00'
。要控制服务器是否允许'0000-00-00'
,请使用NO_ZERO_DATE
模式。)NO_ZERO_IN_DATE
的效果还取决于是否启用了严格 SQL 模式。如果未启用此模式,则允许使用包含零部分的日期,并且插入操作不会产生警告。
如果启用了此模式,则包含零部分的日期将作为
'0000-00-00'
插入,并产生警告。如果启用了此模式和严格模式,则不允许使用包含零部分的日期,并且插入操作会产生错误,除非还指定了
IGNORE
。对于INSERT IGNORE
和UPDATE IGNORE
,则包含零部分的日期将作为'0000-00-00'
插入,并产生警告。
NO_ZERO_IN_DATE
已弃用。NO_ZERO_IN_DATE
不是严格模式的一部分,但应与严格模式结合使用,并且默认情况下启用。如果在未启用严格模式的情况下启用了NO_ZERO_IN_DATE
,反之亦然,则会发出警告。因为
NO_ZERO_IN_DATE
已弃用,所以您应该预计它会在未来的 MySQL 版本中作为单独的模式名称被移除,其效果将包含在严格 SQL 模式的效果中。拒绝选择列表、
HAVING
条件或ORDER BY
列表引用了GROUP BY
子句中未命名且不是GROUP BY
列的函数依赖项(由其唯一确定)的非聚合列的查询。标准 SQL 的 MySQL 扩展允许在
HAVING
子句中引用选择列表中的别名表达式。无论是否启用了ONLY_FULL_GROUP_BY
,HAVING
子句都可以引用别名。有关其他讨论和示例,请参见 第 14.19.3 节“MySQL 处理 GROUP BY”。
默认情况下,检索时会从
CHAR
列值中删除尾随空格。如果启用了PAD_CHAR_TO_FULL_LENGTH
,则不会进行删除,并且检索到的CHAR
值会填充到其完整长度。此模式不适用于VARCHAR
列,因为检索时会保留尾随空格。注意PAD_CHAR_TO_FULL_LENGTH
已弃用。预计它将在未来版本的 MySQL 中被移除。mysql> CREATE TABLE t1 (c1 CHAR(10)); Query OK, 0 rows affected (0.37 sec) mysql> INSERT INTO t1 (c1) VALUES('xy'); Query OK, 1 row affected (0.01 sec) mysql> SET sql_mode = ''; Query OK, 0 rows affected (0.00 sec) mysql> SELECT c1, CHAR_LENGTH(c1) FROM t1; +------+-----------------+ | c1 | CHAR_LENGTH(c1) | +------+-----------------+ | xy | 2 | +------+-----------------+ 1 row in set (0.00 sec) mysql> SET sql_mode = 'PAD_CHAR_TO_FULL_LENGTH'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT c1, CHAR_LENGTH(c1) FROM t1; +------------+-----------------+ | c1 | CHAR_LENGTH(c1) | +------------+-----------------+ | xy | 10 | +------------+-----------------+ 1 row in set (0.00 sec)
对所有存储引擎启用严格 SQL 模式。拒绝无效的数据值。有关详细信息,请参见 严格 SQL 模式。
对事务性存储引擎启用严格 SQL 模式,并在可能的情况下对非事务性存储引擎启用。有关详细信息,请参见 严格 SQL 模式。
控制将具有小数秒部分的
TIME
、DATE
或TIMESTAMP
值插入到具有相同类型但小数位数较少的列中时,是进行舍入还是截断。默认行为是使用舍入。如果启用了此模式,则会改为进行截断。以下语句序列说明了差异CREATE TABLE t (id INT, tval TIME(1)); SET sql_mode=''; INSERT INTO t (id, tval) VALUES(1, 1.55); SET sql_mode='TIME_TRUNCATE_FRACTIONAL'; INSERT INTO t (id, tval) VALUES(2, 1.55);
生成的表内容如下所示,其中第一个值已进行舍入,第二个值已进行截断
mysql> SELECT id, tval FROM t ORDER BY id; +------+------------+ | id | tval | +------+------------+ | 1 | 00:00:01.6 | | 2 | 00:00:01.5 | +------+------------+
另请参见 第 13.2.6 节“时间值中的小数秒”。
以下特殊模式是上述列表中模式值的组合的简写形式。
等效于
REAL_AS_FLOAT
、PIPES_AS_CONCAT
、ANSI_QUOTES
、IGNORE_SPACE
和ONLY_FULL_GROUP_BY
。ANSI
模式还会导致服务器针对以下查询返回错误:对于具有外部引用的集合函数S
,
无法在已针对其解析外部引用的外部查询中聚合。这是一个这样的查询S
(outer_ref
)SELECT * FROM t1 WHERE t1.a IN (SELECT MAX(t1.b) FROM t2 WHERE ...);
在这里,
MAX(t1.b)
无法在外部查询中聚合,因为它出现在该查询的WHERE
子句中。标准 SQL 要求在这种情况下出现错误。如果未启用ANSI
模式,则服务器会在此类查询中将
解释为与解释S
(outer_ref
)
相同的方式。S
(const
)请参见 第 1.7 节“MySQL 标准符合性”。
TRADITIONAL
等效于STRICT_TRANS_TABLES
、STRICT_ALL_TABLES
、NO_ZERO_IN_DATE
、NO_ZERO_DATE
、ERROR_FOR_DIVISION_BY_ZERO
和NO_ENGINE_SUBSTITUTION
。
严格模式控制 MySQL 如何处理数据更改语句(如 INSERT
或 UPDATE
)中的无效值或缺失值。值可能由于多种原因而无效。例如,它可能具有错误的数据类型,或者可能超出范围。当要插入的新行不包含没有显式 DEFAULT
子句的非 NULL
列的值时,该值将丢失。(对于 NULL
列,如果缺少该值,则插入 NULL
。)严格模式还会影响 DDL 语句,如 CREATE TABLE
。
如果未启用严格模式,MySQL 会为无效值或缺失值插入调整后的值,并生成警告(请参见 第 15.7.7.41 节“SHOW WARNINGS 语句”)。在严格模式下,您可以使用 INSERT IGNORE
或 UPDATE IGNORE
生成此行为。
对于不更改数据的语句(如 SELECT
),无效值会在严格模式下生成警告,而不是错误。
严格模式会在尝试创建超过最大密钥长度的密钥时产生错误。如果未启用严格模式,则会导致警告并将密钥截断为最大密钥长度。
严格模式不会影响是否检查外键约束。可以使用 foreign_key_checks
来实现这一点。(请参见 第 7.1.8 节“服务器系统变量”。)
如果启用了 STRICT_ALL_TABLES
或 STRICT_TRANS_TABLES
,则严格 SQL 模式将生效,尽管这些模式的效果略有不同
对于事务性表,如果启用了
STRICT_ALL_TABLES
或STRICT_TRANS_TABLES
,则数据更改语句中的无效值或缺失值会发生错误。该语句将中止并回滚。对于非事务性表,如果错误的值出现在要插入或更新的第一行中,则这两种模式的行为是相同的:语句中止,表保持不变。如果语句插入或修改多行,并且错误值出现在第二行或之后的行中,则结果取决于启用了哪种严格模式
对于
STRICT_ALL_TABLES
,MySQL 返回一个错误并忽略其余行。但是,因为前面的行已经插入或更新,所以结果是部分更新。为了避免这种情况,请使用单行语句,可以在不更改表的情况下中止这些语句。对于
STRICT_TRANS_TABLES
,MySQL 将无效值转换为该列最接近的有效值,并插入调整后的值。如果缺少值,MySQL 将插入列数据类型的隐式默认值。在这两种情况下,MySQL 都会生成警告而不是错误,并继续处理该语句。隐式默认值在 第 13.6 节“数据类型默认值” 中进行了描述。
严格模式会影响对零除、零日期和日期中零的处理,如下所示
严格模式会影响对零除的处理,其中包括
MOD(
N
,0)如果未启用严格模式,则除以零将插入
NULL
并且不产生警告。如果启用了严格模式,则除以零会产生错误,除非还指定了
IGNORE
。对于INSERT IGNORE
和UPDATE IGNORE
,除以零将插入NULL
并产生警告。
对于
SELECT
,除以零将返回NULL
。启用严格模式也会产生警告。严格模式会影响服务器是否允许将
'0000-00-00'
视为有效日期如果未启用严格模式,则允许使用
'0000-00-00'
,并且插入不会产生警告。如果启用了严格模式,则不允许使用
'0000-00-00'
,并且插入会产生错误,除非还指定了IGNORE
。对于INSERT IGNORE
和UPDATE IGNORE
,允许使用'0000-00-00'
,并且插入会产生警告。
严格模式会影响服务器是否允许日期的年份部分不为零,但月份或日期部分为 0(例如
'2010-00-01'
或'2010-01-00'
)如果未启用严格模式,则允许日期的某些部分为零,并且插入不会产生警告。
如果启用了严格模式,则不允许日期的某些部分为零,并且插入会产生错误,除非还指定了
IGNORE
。对于INSERT IGNORE
和UPDATE IGNORE
,将日期的某些部分为零的日期插入为'0000-00-00'
(使用IGNORE
时被视为有效),并产生警告。
有关严格模式和 IGNORE
的更多信息,请参阅 IGNORE 关键字和严格 SQL 模式比较。
严格模式会影响结合 ERROR_FOR_DIVISION_BY_ZERO
、NO_ZERO_DATE
和 NO_ZERO_IN_DATE
模式对零除、零日期和日期中零的处理。
本节比较了 IGNORE
关键字(将错误降级为警告)和严格 SQL 模式(将警告升级为错误)对语句执行的影响。它描述了它们影响哪些语句,以及它们适用于哪些错误。
下表总结了在默认情况下产生错误与产生警告时语句行为的比较。默认情况下产生错误的示例是将 NULL
插入 NOT NULL
列。默认情况下产生警告的示例是将错误数据类型的 value 插入列(例如将字符串 'abc'
插入整数列)。
操作模式 | 语句默认值为错误时 | 语句默认值为警告时 |
---|---|---|
没有 IGNORE 或严格 SQL 模式 |
错误 | 警告 |
使用 IGNORE 时 |
警告 | 警告(与没有 IGNORE 或严格 SQL 模式时相同) |
使用严格 SQL 模式时 | 错误(与没有 IGNORE 或严格 SQL 模式时相同) |
错误 |
使用 IGNORE 和严格 SQL 模式时 |
警告 | 警告 |
从表中得出的一个结论是,当 IGNORE
关键字和严格 SQL 模式都生效时,IGNORE
优先。这意味着,尽管 IGNORE
和严格 SQL 模式可以被认为对错误处理具有相反的影响,但它们一起使用时不会相互抵消。
IGNORE 对语句执行的影响
MySQL 中的几个语句支持可选的 IGNORE
关键字。此关键字会导致服务器将某些类型的错误降级并生成警告。对于多行语句,将错误降级为警告可能会使行得到处理。否则,IGNORE
会导致语句跳到下一行,而不是中止。(对于不可忽略的错误,无论 IGNORE
关键字如何,都会发生错误。)
示例:如果表 t
有一个包含唯一值的主键列 i
,则尝试将相同的 i
值插入多行通常会产生重复键错误
mysql> CREATE TABLE t (i INT NOT NULL PRIMARY KEY);
mysql> INSERT INTO t (i) VALUES(1),(1);
ERROR 1062 (23000): Duplicate entry '1' for key 't.PRIMARY'
使用 IGNORE
时,包含重复键的行仍然不会插入,但会发生警告而不是错误
mysql> INSERT IGNORE INTO t (i) VALUES(1),(1);
Query OK, 1 row affected, 1 warning (0.01 sec)
Records: 2 Duplicates: 1 Warnings: 1
mysql> SHOW WARNINGS;
+---------+------+-----------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------+
| Warning | 1062 | Duplicate entry '1' for key 't.PRIMARY' |
+---------+------+-----------------------------------------+
1 row in set (0.00 sec)
示例:如果表 t2
有一个 NOT NULL
列 id
,则尝试插入 NULL
会在严格 SQL 模式下产生错误
mysql> CREATE TABLE t2 (id INT NOT NULL);
mysql> INSERT INTO t2 (id) VALUES(1),(NULL),(3);
ERROR 1048 (23000): Column 'id' cannot be null
mysql> SELECT * FROM t2;
Empty set (0.00 sec)
如果 SQL 模式不严格,IGNORE
会导致将 NULL
插入为列隐式默认值(在本例中为 0),这使得该行能够在不跳过的情况下得到处理
mysql> INSERT INTO t2 (id) VALUES(1),(NULL),(3);
mysql> SELECT * FROM t2;
+----+
| id |
+----+
| 1 |
| 0 |
| 3 |
+----+
以下语句支持 IGNORE
关键字
CREATE TABLE ... SELECT
:IGNORE
不适用于语句的CREATE TABLE
或SELECT
部分,而是适用于将SELECT
生成的行插入表中。将丢弃在唯一键值上与现有行重复的行。DELETE
:IGNORE
会导致 MySQL 在删除行的过程中忽略错误。INSERT
:使用IGNORE
时,将在唯一键值上与现有行重复的行丢弃。设置为会导致数据转换错误的值的行将设置为最接近的有效值。UPDATE
:使用IGNORE
时,不会更新在唯一键值上发生重复键冲突的行。更新为会导致数据转换错误的值的行将更新为最接近的有效值。
IGNORE
关键字适用于以下可忽略的错误
严格 SQL 模式对语句执行的影响
MySQL 服务器可以在不同的 SQL 模式下运行,并且可以根据 sql_mode
系统变量的值为不同的客户端应用不同的模式。在 “严格” SQL 模式下,服务器会将某些警告升级为错误。
例如,在非严格 SQL 模式下,将字符串 'abc'
插入整数列会导致该值转换为 0 并发出警告
mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO t (i) VALUES('abc');
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> SHOW WARNINGS;
+---------+------+--------------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: 'abc' for column 'i' at row 1 |
+---------+------+--------------------------------------------------------+
1 row in set (0.00 sec)
在严格 SQL 模式下,无效值将被拒绝并产生错误
mysql> SET sql_mode = 'STRICT_ALL_TABLES';
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO t (i) VALUES('abc');
ERROR 1366 (HY000): Incorrect integer value: 'abc' for column 'i' at row 1
有关 sql_mode
系统变量的可能设置的更多信息,请参阅 第 7.1.11 节“服务器 SQL 模式”。
严格 SQL 模式适用于以下语句,在这些语句的条件下,某些值可能超出范围,或者将无效行插入或删除表
在存储程序中,如果在严格模式生效时定义了程序,则上述类型的各个语句将在严格 SQL 模式下执行。
严格 SQL 模式适用于以下错误,这些错误表示一类错误,其中输入值无效或缺失。如果值的数据类型与列不匹配或可能超出范围,则该值无效。如果要插入的新行不包含其定义中没有显式 DEFAULT
子句的 NOT NULL
列的值,则该值缺失。
ER_BAD_NULL_ERROR
ER_CUT_VALUE_GROUP_CONCAT
ER_DATA_TOO_LONG
ER_DATETIME_FUNCTION_OVERFLOW
ER_DIVISION_BY_ZERO
ER_INVALID_ARGUMENT_FOR_LOGARITHM
ER_NO_DEFAULT_FOR_FIELD
ER_NO_DEFAULT_FOR_VIEW_FIELD
ER_TOO_LONG_KEY
ER_TRUNCATED_WRONG_VALUE
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
ER_WARN_DATA_OUT_OF_RANGE
ER_WARN_NULL_TO_NOTNULL
ER_WARN_TOO_FEW_RECORDS
ER_WRONG_ARGUMENTS
ER_WRONG_VALUE_FOR_TYPE
WARN_DATA_TRUNCATED
由于 MySQL 的持续开发会定义新的错误,因此上述列表中可能没有严格 SQL 模式适用的错误。