SQL模式介紹
MySQL服務器可以在不同的SQL操作模式,并能應用這些模式不同的客戶,根據不同的價值SQL模式系統 變量。數據庫管理員可以設置全局SQL模式相匹配的網站服務器操作要求,每個應用程序可以設置會話 SQL模式自身的要求。
SQL模式定義MySQL應支持哪些SQL語法,以及應執行哪種數據驗證檢查。這樣可以更容易地在不同的環境中使用MySQL,并結合其它數據庫服務器使用MySQL。
介紹各SQL模式
ONLY_FULL_GROUP_BY
在嚴格模式下,不要讓GROUP BY部分中的查詢指向未選擇的列,否則報錯。
NO_ZERO_DATE
在嚴格模式,不要將’0000-00-00’做為合法日期。你仍然可以用IGNORE選項插入零日期。在非嚴格模式,可以接受該日期,但會生成警告。
NO_ZERO_IN_DATE
在嚴格模式,不接受月或日部分為0的日期(也就是說比NO_ZERO_DATE),對年不限制。如果使用IGNORE選項,我們為類似的日期插入’0000-00-00’。在非嚴格模式,可以接受該日期,但會生成警告。
ERROR_FOR_DIVISION_BY_ZERO
在嚴格模式,在INSERT或UPDATE過程中,如果被零除(或MOD(X,0)),則產生錯誤(否則為警告)。如果未給出該模式,被零除時MySQL返回NULL。如果用到INSERT IGNORE或UPDATE IGNORE中,MySQL生成被零除警告,但操作結果為NULL。
NO_AUTO_CREATE_USER
在嚴格模式下,防止GRANT自動創建新用戶,除非還指定了密碼。
NO_ENGINE_SUBSTITUTION
如果需要的存儲引擎被禁用或未編譯,可以防止自動替換存儲引擎。
STRICT_TRANS_TABLES
為事務存儲引擎啟用嚴格模式,也可能為非事務存儲引擎啟用嚴格模式,非法數據值被拒絕,下面有詳細說明。
嚴格模式控制MySQL如何處理非法或丟失的輸入值。有幾種原因可以使一個值為非法。例如,數據類型錯誤,不適合列,或超出范圍。當新插入的行不包含某列的沒有顯示定義DEFAULT子句的值,則該值被丟失。
對于事務表,當啟用STRICT_ALL_TABLES或STRICT_TRANS_TABLES模式時,如果語句中有非法或丟失值,則會出現錯誤。語句被放棄并滾動。
對于非事務表,如果插入或更新的第1行出現壞值,兩種模式的行為相同。語句被放棄,表保持不變。如果語句插入或修改多行,并且壞值出現在第2或后面的行,結果取決于啟用了哪個嚴格選項:
對于STRICT_ALL_TABLES,MySQL返回錯誤并忽視剩余的行。但是,在這種情況下,前面的行已經被插入或更新。這說明你可以部分更新,這可能不是你想要的。要避免這點,最好使用單行語句,因為這樣可以不更改表即可以放棄。
對于STRICT_TRANS_TABLES,MySQL將非法值轉換為最接近該列的合法值并插入調整后的值。如果值丟失,MySQL在列中插入隱式 默認值。在任何情況下,MySQL都會生成警告而不是給出錯誤并繼續執行語句。
嚴格模式不允許非法日期,例如’2004-04-31’。它不允許禁止日期使用“零”部分,例如’2004-04-00’或”零”日期。要想禁止,應在嚴格模式基礎上,啟用NO_ZERO_IN_DATE和NO_ZERO_DATE SQL模式。
如果你不使用嚴格模式(即不啟用STRICT_TRANS_TABLES或STRICT_ALL_TABLES模式),對于非法或丟失的值,MySQL將插入調整后的值并給出警告。在嚴格模式,你可以通過INSERT IGNORE或UPDATE IGNORE來實現。
ANSI
更改語法和行為,使其更符合標準SQL。
TRADITIONAL
Make MySQL的行為象“傳統”SQL數據庫系統。該模式的簡單描述是當在列中插入不正確的值時“給出錯誤而不是警告”。注釋:一旦發現錯誤立即放棄INSERT/UPDATE。如果你使用非事務存儲引擎,這種方式不是你想要的,因為出現錯誤前進行的數據更改不會“滾動”,結果是更新“只進行了一部分”。
ALLOW_INVALID_DATES
在嚴格模式下不要檢查全部日期。只檢查1到12之間的月份和1到31之間的日。這在Web應用程序中,當你從三個不同的字段獲取年、月、日,并且想要確切保存用戶插入的內容(不進行日期驗證)時很重要。該模式適用于DATE和DATETIME列。不適合TIMESTAMP列,TIMESTAMP列需要驗證日期。
啟用嚴格模式后,服務器需要合法的月和日,不僅僅是分別在1到12和1到31范圍內。例如,禁用嚴格模式時’2004-04-31’是合法的,但啟用嚴格模式后是非法的。要想在嚴格模式允許遮掩固定日期,還應啟用ALLOW_INVALID_DATES。
ANSI_QUOTES
將‘”‘視為識別符引號(‘`’引號字符),不要視為字符串的引號字符。在ANSI模式,你可以仍然使用‘`’來引用識別符。啟用ANSI_QUOTES后,你不能用雙引號來引用字符串,因為它被解釋為識別符。
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_PRECEDENCESQL模式,可以獲得以前的更高優先級的結果。
IGNORE_SPACE
允許函數名和‘(‘之間有空格。強制將所有函數名視為保存的字。結果是,如果你想要訪問保存為字的數據庫、表或列名,你必須引用它。例如,因為有USER()函數,mysql數據庫中的user表名和該表內的User列被保存下來,因此你必須引用它們.
NO_AUTO_VALUE_ON_ZERO
NO_AUTO_VALUE_ON_ZERO影響AUTO_INCREMENT列的處理。一般情況,你可以向該列插入NULL或0生成下一個序列號。NO_AUTO_VALUE_ON_ZERO禁用0,因此只有NULL可以生成下一個序列號。
如果將0保存到表的AUTO_INCREMENT列,該模式會很有用。(不推薦采用該慣例)。例如,如果你用mysqldump轉儲表并重載,MySQL遇到0值一般會生成新的序列號,生成的表的內容與轉儲的表不同。重載轉儲文件前啟用NO_AUTO_VALUE_ON_ZERO可以解決該問題。mysqldump在輸出中自動包括啟用NO_AUTO_VALUE_ON_ZERO的語句。
NO_BACKSLASH_ESCAPES
禁用反斜線字符(‘\’)做為字符串內的退出字符。啟用該模式,反斜線則成為普通字符。
NO_DIR_IN_CREATE
創建表時,忽視所有INDEX DIRECTORY和DATA DIRECTORY指令。該選項對從復制服務器有用。
NO_ENGINE_SUBSTITUTION
如果需要的存儲引擎被禁用或未編譯,可以防止自動替換存儲引擎。
NO_FIELD_OPTIONS
不要在SHOW CREATE TABLE的輸出中打印MySQL專用列選項。該模式在可移植模式(portability mode)下用于mysqldump。
NO_KEY_OPTIONS
不要在SHOW CREATE TABLE的輸出中打印MySQL專用索引選項。該模式在可移植模式(portability mode)下用于mysqldump。
NO_TABLE_OPTIONS
不要在SHOW CREATE TABLE的輸出中打印MySQL專用表選項(例如ENGINE)。該模式在可移植模式(portability mode)下用于mysqldump。
NO_UNSIGNED_SUBTRACTION
在減運算中,如果某個操作數沒有符號,不要將結果標記為UNSIGNED。請注意這樣使UNSIGNED BIGINT不能100%用于上下文中。參見12.8節,“Cast函數和操作符”。
PIPES_AS_CONCAT
將||視為字符串連接操作符(+)(同CONCAT()),而不視為OR。
REAL_AS_FLOAT
將REAL視為FLOAT的同義詞,而不是DOUBLE的同義詞。
SQL模式測試
一、查看當前SQL模式
來看一下MySQL 5.6&5.7的默認SQL模式
# MySQL 5.6 Default SQL_MODE;
mysql> select @@sql_mode;
+--------------------------------------------+
| @@sql_mode???????????????????????????????? |
+--------------------------------------------+
| STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
+--------------------------------------------+
1 row in set (0.00 sec)
# MySQL 5.7 Default SQL_MODE;
mysql> select @@sql_mode;
+-------------------------------------------------------------------------------------------------------------------------------------------+
| @@sql_mode????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????|
+-------------------------------------------------------------------------------------------------------------------------------------------+
| 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 |
+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
MySQL 5.7對數據的嚴謹性和一致性上比之前版本要提升很多
二、指定模式
你可以在配置文件中用:
1sql_mode = "modes"
選項啟動mysqld來設置默認SQL模式,modes是用逗號(‘,’)間隔開的一系列不同的模式。如果你想要重設,該值還可以為空(sql-mode =””)。
你還可以動態改變SQL模式:
1SET [SESSION|GLOBAL] sql_mode='modes'
設置GLOBAL變量時需要擁有SUPER權限,并且會影響從那時起連接的所有客戶端的操作。設置SESSION變量只影響當前的客戶端。任何客戶端可以隨時更改自己的會話sql_mode值。
三、示例演示
1.在嚴格的模式下
mysql> create table tbl_kenyon(id int null,vname varchar(6));
Query OK, 0 rows affected (0.12 sec)
mysql> insert into tbl_kenyon values(1,'123456');
Query OK, 1 row affected (0.00 sec)
mysql> insert into tbl_kenyon values(1,'1234567');
ERROR 1406 (22001): Data too long for column 'vname' at row 1
mysql> insert into tbl_kenyon values('','123456');
ERROR 1366 (HY000): Incorrect integer value: '' for column 'id' at row 1
mysql> insert into tbl_kenyon values(null,'123456');
Query OK, 1 row affected (0.01 sec)
2.在非嚴格的模式下
mysql> set @@sql_mode='';
Query OK, 0 rows affected (0.00 sec)
mysql> insert into tbl_kenyon values(99,'123456');
Query OK, 1 row affected (0.00 sec)
mysql> insert into tbl_kenyon values(1,'1234567');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> insert into tbl_kenyon values('','123456');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+------------------------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: '' for column 'id' at row 1 |
+---------+------+------------------------------------------------------+
1 row in set (0.00 sec)
四、 應用場景
兩種模式各有利弊,通常生產上會設置嚴格模式,可以保證數據的完整性。非嚴格模式并不一定就是差的,在數據一致性要求不嚴的場景下某些忽略警告操作可能更方便,比如不同版本數據庫的非關鍵數據導入:
mysql> load data infile '/data/source_data/trace/tbl_msg.sql' into table tbl_msg;
ERROR 1366 (HY000): Incorrect integer value: 'NULL' for column 'pid' at row 1
換個模式導入:
mysql> set @@session.sql_mode='';
Query OK, 0 rows affected (0.00 sec)
mysql> load data infile '/data/source_data/trace/ tbl_msg.sql' into table tbl_msg;
Query OK, 23525 rows affected, 65535 warnings (2.80 sec)
Records: 23525 Deleted: 0 Skipped: 0 Warnings: 185707
轉自:http://www.ywnds.com/?p=7049