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
表進行額外的錯誤檢查 。
在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
。
這些模式被添加到MySQL 5.7中的默認SQL模式中: 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_mode
價值可能是這些:
此模式更改語法和行爲以更貼近地符合標準SQL。它是 本節末尾列出的特殊 組合模式之一。
如果無法將某個值插入到事務表中,請中止該語句。對於非事務性表,如果該值出現在單行語句或多行語句的第一行中,則放棄該語句。更多細節在本節後面給出。
從MySQL 5.7.5開始,默認的SQL模式包括
STRICT_TRANS_TABLES
。讓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
模式影響零除的處理,其中包括 。對於數據更改操作(, ),其效果還取決於是否啓用嚴格的SQL模式。MOD(
N
,0)INSERT
UPDATE
如果此模式未啓用,則按零插入
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
在未啓用嚴格模式的情況下啓用警告, 反之亦然。有關其他討論,請參閱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節“創建用戶語法”, 第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
指定禁用或未編譯的存儲引擎。默認情況下,
NO_ENGINE_SUBSTITUTION
已啓用。由於存儲引擎在運行時可以插入,因此不可用的引擎也會以同樣的方式處理:
如果
NO_ENGINE_SUBSTITUTION
禁用,CREATE TABLE
則使用默認引擎,如果所需引擎不可用,則會發生警告。因爲ALTER TABLE
,發生警告並且表格未被更改。與
NO_ENGINE_SUBSTITUTION
啓用,則會出現錯誤,並且不會創建或修改的表,如果所需的引擎不可用。不要在輸出中打印MySQL特定的列選項
SHOW CREATE TABLE
。這種模式在可移植性模式下由mysqldump使用。注意從MySQL 5.7.22開始,
NO_FIELD_OPTIONS
已被棄用。它將在未來版本的MySQL中被刪除。不要在輸出中打印MySQL特定的索引選項
SHOW CREATE TABLE
。這種模式在可移植性模式下由mysqldump使用。注意從MySQL 5.7.22開始,
NO_KEY_OPTIONS
已被棄用。它將在未來版本的MySQL中被刪除。不要
ENGINE
在輸出中打印MySQL特定的表選項(如 )SHOW CREATE TABLE
。這種模式在可移植性模式下由mysqldump使用。注意從MySQL 5.7.22開始,
NO_TABLE_OPTIONS
已被棄用。它將在未來版本的MySQL中被刪除。整數值之間的減法(其中一個是類型的
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 SELECT c1 - 1 AS c2 FROM test; mysql> DESCRIBE t2; +-------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------------+------+-----+---------+-------+ | c2 | bigint(21) | NO | | 0 | | +-------+------------+------+-----+---------+-------+
這意味着
BIGINT UNSIGNED
在所有情況下都不是100%可用。請參見 第12.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
在未啓用嚴格模式的情況下啓用警告, 反之亦然。有關其他討論,請參閱 MySQL 5.7中的SQL模式更改。由於
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
在未啓用嚴格模式的情況下啓用警告, 反之亦然。有關其他討論,請參閱 MySQL 5.7中的SQL模式更改。由於
NO_ZERO_IN_DATE
已被棄用,它將在未來的MySQL版本中作爲單獨的模式名稱被刪除,其影響包含在嚴格SQL模式的影響中。拒絕對選擇列表,
HAVING
條件或ORDER BY
列表引用既未在GROUP BY
子句中命名也未在功能上依賴(由GROUP BY
列唯一確定)的非 聚合列的查詢。從MySQL 5.7.5開始,默認的SQL模式包括
ONLY_FULL_GROUP_BY
。(在5.7.5之前,MySQL沒有檢測到函數依賴關係,並且ONLY_FULL_GROUP_BY
默認情況下未啓用。關於5.7.5之前的行爲描述,請參閱MySQL 5.6參考手冊。)對標準SQL的MySQL擴展允許在
HAVING
子句中引用 選擇列表中的別名表達式。在MySQL 5.7.5之前,啓用ONLY_FULL_GROUP_BY
禁用這個擴展,因此需要HAVING
使用非混淆表達式來寫入子句。從MySQL 5.7.5開始,解除了這個限制,這樣HAVING
子句可以引用別名,而不管是否ONLY_FULL_GROUP_BY
啓用。有關其他討論和示例,請參見 第12.19.3節“MySQL處理GROUP BY”。
默認情況下,尾部空格
CHAR
在檢索時從列值中刪除 。如果PAD_CHAR_TO_FULL_LENGTH
啓用,則不會發生修剪,並將檢索CHAR
值填充到全長。此模式不適VARCHAR
用於在檢索時保留尾部空格的列。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模式。
從MySQL 5.7.4通過5.7.7,
STRICT_ALL_TABLES
包括的效果ERROR_FOR_DIVISION_BY_ZERO
,NO_ZERO_DATE
和NO_ZERO_IN_DATE
模式。有關其他討論,請參閱 MySQL 5.7中的SQL模式更改。爲事務性存儲引擎啓用嚴格SQL模式,並在可能的情況下爲非事務性存儲引擎啓用。有關詳細信息,請參閱嚴格SQL模式。
從MySQL 5.7.4通過5.7.7,
STRICT_TRANS_TABLES
包括的效果ERROR_FOR_DIVISION_BY_ZERO
,NO_ZERO_DATE
和NO_ZERO_IN_DATE
模式。有關其他討論,請參閱 MySQL 5.7中的SQL模式更改。
提供以下特殊模式作爲上述列表中模式值組合的簡寫。
相當於
REAL_AS_FLOAT
,PIPES_AS_CONCAT
,ANSI_QUOTES
,IGNORE_SPACE
,和(從MySQL 5.7.5的)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
)相當於
PIPES_AS_CONCAT
,ANSI_QUOTES
,IGNORE_SPACE
,NO_KEY_OPTIONS
,NO_TABLE_OPTIONS
,NO_FIELD_OPTIONS
。注意從MySQL 5.7.22開始,
DB2
已被棄用。它將在未來版本的MySQL中被刪除。相當於
PIPES_AS_CONCAT
,ANSI_QUOTES
,IGNORE_SPACE
,NO_KEY_OPTIONS
,NO_TABLE_OPTIONS
,NO_FIELD_OPTIONS
,NO_AUTO_CREATE_USER
。注意從MySQL 5.7.22開始,
MAXDB
已被棄用。它將在未來版本的MySQL中被刪除。相當於
PIPES_AS_CONCAT
,ANSI_QUOTES
,IGNORE_SPACE
,NO_KEY_OPTIONS
,NO_TABLE_OPTIONS
,NO_FIELD_OPTIONS
。注意從MySQL 5.7.22開始,
MSSQL
已被棄用。它將在未來版本的MySQL中被刪除。等同於
MYSQL323
,HIGH_NOT_PRECEDENCE
。這意味着HIGH_NOT_PRECEDENCE
加上一些SHOW CREATE TABLE
特定的行爲MYSQL323
:注意從MySQL 5.7.22開始,
MYSQL323
已被棄用。它將在未來版本的MySQL中被刪除。等同於
MYSQL40
,HIGH_NOT_PRECEDENCE
。這意味着HIGH_NOT_PRECEDENCE
加上一些特定的行爲MYSQL40
。MYSQL323
除了SHOW CREATE TABLE
不HEAP
作爲MEMORY
表格的存儲引擎顯示之外,它們與for相同。注意從MySQL 5.7.22開始,
MYSQL40
已被棄用。它將在未來版本的MySQL中被刪除。相當於
PIPES_AS_CONCAT
,ANSI_QUOTES
,IGNORE_SPACE
,NO_KEY_OPTIONS
,NO_TABLE_OPTIONS
,NO_FIELD_OPTIONS
,NO_AUTO_CREATE_USER
。注意從MySQL 5.7.22開始,
ORACLE
已被棄用。它將在未來版本的MySQL中被刪除。相當於
PIPES_AS_CONCAT
,ANSI_QUOTES
,IGNORE_SPACE
,NO_KEY_OPTIONS
,NO_TABLE_OPTIONS
,NO_FIELD_OPTIONS
。注意從MySQL 5.7.22開始,
POSTGRESQL
已被棄用。它將在未來版本的MySQL中被刪除。MySQL的5.7.4之前,以及在MySQL 5.7.8或更高版本,
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
。從MySQL 5.7.4雖然5.7.7,
TRADITIONAL
相當於STRICT_TRANS_TABLES
,STRICT_ALL_TABLES
,NO_AUTO_CREATE_USER
,和NO_ENGINE_SUBSTITUTION
。這些NO_ZERO_IN_DATE
,NO_ZERO_DATE
和ERROR_FOR_DIVISION_BY_ZERO
模式沒有命名,因爲在這些版本中,它們的效果包含在嚴格SQL模式(STRICT_ALL_TABLES
或STRICT_TRANS_TABLES
)的效果中。因此,TRADITIONAL
所有MySQL 5.7版本的效果 都是一樣的(和MySQL 5.6中的相同)。有關其他討論,請參閱 MySQL 5.7中的SQL模式更改。
嚴格模式控制MySQL如何處理數據更改語句(如INSERT
or)中的 無效值或缺失值 UPDATE
。由於多種原因,值可能無效。例如,它可能具有該列的錯誤數據類型,或者它可能超出範圍。當要插入的新行不包含定義中NULL
沒有顯式DEFAULT
子句的非列 的值時,缺少值。(對於 NULL
列,NULL
如果值缺失則插入。)嚴格模式也會影響DDL語句,如CREATE TABLE
。
如果嚴格模式沒有生效,MySQL會爲無效值或缺失值插入調整值併產生警告(請參見 第13.7.5.40節“SHOW WARNINGS Syntax”)。在嚴格模式下,您可以使用INSERT IGNORE
或生成此行爲 UPDATE IGNORE
。
對於SELECT
不會更改數據的語句,無效值將在嚴格模式下生成警告,而不是錯誤。
對於嘗試創建超過最大密鑰長度的密鑰的嚴格模式會產生錯誤。如果嚴格模式未啓用,則會導致警告並將密鑰截斷爲最大密鑰長度。
嚴格模式不影響是否檢查外鍵約束。foreign_key_checks
可以用於此。(請參見 第5.1.5節“服務器系統變量”。)
如果啓用了STRICT_ALL_TABLES
或者 STRICT_TRANS_TABLES
已啓用嚴格SQL模式 ,但這些模式的效果有所不同:
對於事務性表,當啓用
STRICT_ALL_TABLES
或STRICT_TRANS_TABLES
啓用數據更改語句時,無效值或缺失值會發生錯誤 。該聲明被中止並回滾。對於非事務性表,如果在要插入或更新的第一行中出現錯誤值,那麼對於任一模式的行爲都是相同的:語句被中止並且表保持不變。如果語句插入或修改多行,並且第二行或更後一行中出現錯誤值,則結果取決於啓用了哪個嚴格模式:
因爲
STRICT_ALL_TABLES
,MySQL返回一個錯誤並忽略其餘的行。但是,因爲較早的行已被插入或更新,所以結果是部分更新。爲避免這種情況,請使用單行語句,該語句可以在不更改表格的情況下中止。因爲
STRICT_TRANS_TABLES
,MySQL會將無效值轉換爲列的最接近的有效值並插入調整後的值。如果缺少一個值,MySQL將插入列數據類型的隱式默認值。無論哪種情況,MySQL都會生成警告而不是錯誤,並繼續處理該語句。第11.7節“數據類型默認值”中介紹了隱式默認值。
嚴格模式會影響日期中除零,零日期和零的處理,如下所示:
嚴格模式影響零除的處理,其中包括 :
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'
or'2010-01-00'
)的日期:如果嚴格模式未啓用,則允許零部件的日期,並且插入不會產生警告。
如果啓用了嚴格模式,則不允許使用零部件的日期,除非
IGNORE
給出嚴格模式,否則插入會產生錯誤 。對於INSERT IGNORE
和UPDATE IGNORE
,具有零部件的日期被插入'0000-00-00'
(這被認爲是有效的IGNORE
)併產生警告。
有關嚴格模式的更多信息 IGNORE
,請參閱 IGNORE關鍵字和嚴格SQL模式的比較。
MySQL的5.7.4之前,以及在MySQL 5.7.8或更高版本,嚴格模式是零,零日期,並在日期零與一起影響部門的處理ERROR_FOR_DIVISION_BY_ZERO
, NO_ZERO_DATE
和 NO_ZERO_IN_DATE
模式。從MySQL 5.7.4儘管5.7.7的ERROR_FOR_DIVISION_BY_ZERO
, NO_ZERO_DATE
以及 NO_ZERO_IN_DATE
明確命名及其影響都包括在嚴格模式的影響時模式什麼也不做。有關其他討論,請參閱 MySQL 5.7中的SQL模式更改。
本節比較IGNORE
關鍵字(將錯誤降級爲警告)和嚴格SQL模式(將警告升級爲錯誤)的語句執行效果 。它描述了它們影響哪些語句,以及它們適用於哪些錯誤。
下表列出了默認情況下產生錯誤與警告時語句行爲的總結比較。默認情況下產生錯誤的一個示例是將a插入NULL
到NOT NULL
列中。默認情況下產生警告的一個示例是將錯誤數據類型的值插入列(例如將字符串插入 'abc'
到整數列中)。
操作模式 | 當語句默認爲錯誤時 | 當語句默認爲警告時 |
---|---|---|
沒有IGNORE 或嚴格的SQL模式 | 錯誤 | 警告 |
同 IGNORE | 警告 | 警告(與沒有IGNORE 或嚴格的SQL模式相同) |
採用嚴格的SQL模式 | 錯誤(與沒有IGNORE 或嚴格的SQL模式相同) | 錯誤 |
採用IGNORE 嚴格的SQL模式 | 警告 | 警告 |
從表中得出的一個結論是,當 IGNORE
關鍵字和嚴格SQL模式都有效時,IGNORE
優先。這意味着,儘管IGNORE
嚴格的SQL模式可以被認爲對錯誤處理有相反的效果,但它們在一起使用時不會取消。
IGNORE對陳述執行的影響
MySQL中的幾個語句支持一個可選的 IGNORE
關鍵字。此關鍵字會導致服務器降級某些類型的錯誤並生成警告。對於多行語句, IGNORE
會導致語句跳到下一行而不是中止。
例如,如果表t
具有主鍵列i
,則嘗試將相同的值i
插入多行中通常會產生重複鍵錯誤:
mysql> INSERT INTO t (i) VALUES(1),(1);
ERROR 1062 (23000): Duplicate entry '1' for key '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 'PRIMARY' |
+---------+------+---------------------------------------+
1 row in set (0.00 sec)
這些語句支持IGNORE
關鍵字:
CREATE TABLE ... SELECT
:IGNORE
不適用於聲明CREATE TABLE
或SELECT
部分聲明,而是插入到由聲明產生的行表中SELECT
。丟棄在唯一鍵值上覆制現有行的行。DELETE
:IGNORE
導致MySQL在刪除行的過程中忽略錯誤。INSERT
:使用IGNORE
,丟棄在唯一鍵值上覆制現有行的行。將設置爲會導致數據轉換錯誤的值設置爲最接近的有效值。UPDATE
:與IGNORE
,在唯一鍵值上發生重複鍵衝突的行不會更新。行更新爲將導致數據轉換錯誤的值更新爲最接近的有效值。
該IGNORE
關鍵字適用於以下錯誤:
ER_BAD_NULL_ERROR
ER_DUP_ENTRY
ER_DUP_ENTRY_WITH_KEY_NAME
ER_DUP_KEY
ER_NO_PARTITION_FOR_GIVEN_VALUE
ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT
ER_NO_REFERENCED_ROW_2
ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET
ER_ROW_IS_REFERENCED_2
ER_SUBQUERY_NO_1_ROW
ER_VIEW_CHECK_FAILED
嚴格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
系統變量的可能設置的更多信息 ,請參見 第5.1.8節“服務器SQL模式”。
嚴格SQL模式適用於下列語句,在某些條件下某些值可能超出範圍,或者將無效行插入或從表中刪除:
在存儲的程序中,如果程序是在嚴格模式生效的情況下定義的,那麼剛剛列出的類型的單個語句將以嚴格的SQL模式執行。
嚴格SQL模式適用於以下錯誤,表示輸入值無效或缺失的一類錯誤。如果該列的數據類型錯誤或者可能超出範圍,則該值無效。如果要插入的新行不包含定義中NOT NULL
沒有顯式DEFAULT
子句的列 的值,則缺少值。
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 22年7月5日,這些SQL模式被取消,並將在MySQL的未來版本中刪除: DB2
, MAXDB
, MSSQL
, MYSQL323
, MYSQL40
,ORACLE
, POSTGRESQL
, NO_FIELD_OPTIONS
, NO_KEY_OPTIONS
, NO_TABLE_OPTIONS
。
在MySQL 5.7中,ONLY_FULL_GROUP_BY
默認情況下啓用了 SQL模式,因爲GROUP BY
處理變得更加複雜,包括檢測功能依賴關係。但是,如果您發現已 ONLY_FULL_GROUP_BY
啓用導致現有應用程序的查詢被拒絕,則這些操作中的任何一個都應該恢復操作:
如果可以修改有問題的查詢,請這麼做,以便非聚合列在功能上依賴於
GROUP BY
列,或者通過使用非聚合列引用ANY_VALUE()
。如果無法修改違規查詢(例如,如果它是由第三方應用程序生成的),請
sql_mode
在服務器啓動時將系統變量設置爲不啓用ONLY_FULL_GROUP_BY
。
在MySQL 5.7中, ERROR_FOR_DIVISION_BY_ZERO
, NO_ZERO_DATE
,和 NO_ZERO_IN_DATE
SQL模式已被棄用。長期計劃是將三種模式納入嚴格的SQL模式,並將其作爲未來MySQL版本中的顯式模式進行移除。爲了兼容MySQL 5.7和MySQL 5.6嚴格模式併爲受影響的應用程序提供更多時間修改,以下行爲適用:
ERROR_FOR_DIVISION_BY_ZERO
,NO_ZERO_DATE
並且NO_ZERO_IN_DATE
不是嚴格SQL模式的一部分,但它旨在與嚴格模式一起使用。提醒一下,如果在未啓用嚴格模式的情況下啓用警告,則會發生警告,反之亦然。ERROR_FOR_DIVISION_BY_ZERO
,,NO_ZERO_DATE
並且NO_ZERO_IN_DATE
默認啓用。
通過上述更改,默認情況下仍會啓用更嚴格的數據檢查,但可以在當前希望或必須執行此操作的環境中禁用各個模式