- 一 、聲明
- 二 、SQL_MODE參數值
- 三 、設置 sql_mode
一、 聲明
? ??原文:https://segmentfault.com/a/1190000005936172
二 、SQL_MODE參數值
官方手冊專門有一節介紹?https://dev.mysql.com/doc/refman/5.6/en/sql-mode.html?。 SQL Mode 定義了兩個方面:MySQL應支持的SQL語法,以及應該在數據上執行何種確認檢查。
1. SQL語法支持類
-
ONLY_FULL_GROUP_BY
?對于GROUP BY聚合操作,如果在SELECT中的列、HAVING或者ORDER BY子句的列,沒有在GROUP BY中出現,那么這個SQL是不合法的。是可以理解的,因為不在 group by 的列查出來展示會有矛盾。
在5.7中默認啟用,所以在實施5.6升級到5.7的過程需要注意:
Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column '1066export.ebay_order_items.TransactionID' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
-
ANSI_QUOTES
?啟用 ANSI_QUOTES 后,不能用雙引號來引用字符串,因為它被解釋為識別符,作用與 ` 一樣。設置它以后,update t set f1="" ...
,會報 Unknown column '' in 'field list 這樣的語法錯誤。 -
MySQL in,
PIPES_AS_CONCAT
?將?||
?視為字符串的連接操作符而非 或 運算符,這和Oracle數據庫是一樣的,也和字符串的拼接函數 CONCAT() 相類似。 -
NO_TABLE_OPTIONS
?使用?SHOW CREATE TABLE
?時不會輸出MySQL特有的語法部分,如?ENGINE
?,這個在使用 mysqldump 跨DB種類遷移的時候需要考慮。 -
NO_AUTO_CREATE_USER
?字面意思不自動創建用戶。在給MySQL用戶授權時,我們習慣使用?GRANT ... ON ... TO dbuser
?順道一起創建用戶。設置該選項后就與oracle操作類似,授權之前必須先建立用戶。5.7.7開始也默認了。
2. 數據檢查類
-
NO_ZERO_DATE
?認為日期 '0000-00-00' 非法,與是否設置后面的嚴格模式有關。-
如果設置了嚴格模式,則 NO_ZERO_DATE 自然滿足。但如果是 INSERT IGNORE 或 UPDATE IGNORE,'0000-00-00'依然允許且只顯示warning
-
MySQL decode,如果在非嚴格模式下,設置了
NO_ZERO_DATE
,效果與上面一樣,'0000-00-00'允許但顯示warning;如果沒有設置NO_ZERO_DATE
,no warning,當做完全合法的值。 -
NO_ZERO_IN_DATE
情況與上面類似,不同的是控制日期和天,是否可為 0 ,即?2010-01-00
?是否合法。
-
-
NO_ENGINE_SUBSTITUTION
?使用?ALTER TABLE
或CREATE TABLE
?指定 ENGINE 時, 需要的存儲引擎被禁用或未編譯,該如何處理。啟用NO_ENGINE_SUBSTITUTION
時,那么直接拋出錯誤;不設置此值時,CREATE用默認的存儲引擎替代,ATLER不進行更改,并拋出一個 warning . -
STRICT_TRANS_TABLES
?設置它,表示啟用嚴格模式。?
很多集成環境自帶的MySQL貌似都沒有開啟MySQL的嚴格模式,何為MySQL的嚴格模式,簡單來說就是MySQL自身對數據進行嚴格的校驗(格式、長度、類型等),比如一個整型字段我們寫入一個字符串類型的數據,在非嚴格模式下MySQL不會報錯,同樣如果定義了char或varchar類型的字段,當寫入或更新的數據超過了定義的長度也不會報錯。
我認為這個對于編程來說沒有任何好處,雖然我們盡量在代碼中做數據校驗。MySQL開啟了嚴格模式從一定程序上來講是對我們代碼的一種測試,如果我們的開發環境沒有開啟嚴格模式在開發過程中也沒有遇到錯誤,那么在上線或代碼移植的時候將有可能出現不兼容的情況,因此在開發過程做最好開啟MySQL的嚴格模式。
注意?STRICT_TRANS_TABLES
?不是幾種策略的組合,單獨指?INSERT
、UPDATE
出現少值或無效值該如何處理:
-
sql_mode,如果把 '' 傳給int,嚴格模式下非法,若啟用非嚴格模式則變成0,產生一個warning
-
Out Of Range,變成插入最大邊界值
-
A value is missing when a new row to be inserted does not contain a value for a non-NULL column that has no explicit DEFAULT clause in its definition
-
上面并沒有囊括所有的 SQL Mode,選了幾個代表性的,詳細還是?看手冊。
sql_mode一般來說很少去關注它,沒有遇到實際問題之前不會去啟停上面的條目。我們常設置的 sql_mode 是?ANSI
、STRICT_TRANS_TABLES
、TRADITIONAL
,ansi和traditional是上面的幾種組合。
-
ANSI
:更改語法和行為,使其更符合標準SQL
相當于REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE -
jdbc驅動設置sqlmode。
TRADITIONAL
:更像傳統SQL數據庫系統,該模式的簡單描述是當在列中插入不正確的值時“給出錯誤而不是警告”。
相當于 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 -
ORACLE
:相當于 PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS, NO_AUTO_CREATE_USER
無論何種mode,產生error之后就意味著單條sql執行失敗,對于支持事務的表,則導致當前事務回滾;但如果沒有放在事務中執行,或者不支持事務的存儲引擎表,則可能導致數據不一致。MySQL認為,相比直接報錯終止,數據不一致問題更嚴重。于是?STRICT_TRANS_TABLES
?對非事務表依然盡可能的讓寫入繼續,比如給個"最合理"的默認值或截斷。而對于?STRICT_ALL_TABLES
,如果是單條更新,則不影響,但如果更新的是多條,第一條成功,后面失敗則會出現部分更新。
5.6.6 以后版本默認就是NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
,5.5默認為 '' 。
三 、設置 sql_mode
查看
#1、查看當前連接會話的sql模式: mysql> select @@session.sql_mode; 或者從環境變量里取 mysql> show variables like "sql_mode";#2、查看全局sql_mode設置: mysql> select @@global.sql_mode; 只設置global,需要重新連接進來才會生效
設置
#形式如 mysql> set sql_mode=''; mysql> set global sql_mode='NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES';#如果是自定義的模式組合,可以像下面這樣 Adding only one mode to sql_mode without removing existing ones: mysql> SET sql_mode=(SELECT CONCAT(@@sql_mode,',<mode_to_add>'));Removing only a specific mode from sql_mode without removing others: mysql> SET sql_mode=(SELECT REPLACE(@@sql_mode,'<mode_to_remove>',''));#配置文件里面設置 sql-mode=""
mysql模式。?