- 論壇徽章:
- 0
|
1.8.5. MySQL與標準SQL的差別
1.8.5.1. 子查詢
1.8.5.2. SELECT INTO TABLE
1.8.5.3. 事務和原子操作
1.8.5.4. 存儲程序和觸發(fā)程序
1.8.5.5. 外鍵
1.8.5.6. 視圖
1.8.5.7. ‘--’作為注釋起始標記
我們試圖使MySQL服務器遵從ANSI SQL標準和ODBC SQL標準,但在某些情況下MySQL服務器執(zhí)行的操作有所不同:
· 對于VARCHAR列,存儲值時刪除了尾部空間。(在MySQL 5.0.3中更正)。請參見A.8節(jié),“MySQL中的已知事宜”。
· 在某些情況下,定義表或更改其結構時,將CHAR列轉(zhuǎn)換為VARCHAR列。(在MySQL 5.0.3中更正)。請參見13.1.5.1節(jié),“沉寂的列規(guī)格變更”。
· 刪除表時,不自動取消關于表的權限。必須明確發(fā)出REVOKE語句,以撤銷針對表的權限。請參見13.5.1.3節(jié),“GRANT和REVOKE語法”。
· CAST()函數(shù)不支持對REAL或BIGINT的拋棄。請參見12.8節(jié),“Cast函數(shù)和操作符”。
· 標準SQL要求,SELECT語句中的HAVING子句能夠引用GROUP BY子句中的列。在MySQL 5.0.2之前,不能完成該功能。
1.8.5.1. 子查詢
MySQL 4.1支持子查詢和導出表!白硬樵儭敝傅氖乔短自诹硪徽Z句中的SELECT語句!皩С霰怼保ㄎ疵晥D)是另一語句的FROM子句中的子查詢。請參見13.2.8節(jié),“Subquery語法”。
從MySQL 4.1版起,可以使用聯(lián)合或其他方法重寫大多數(shù)子查詢。關于如何完成該任務的更多信息,請參見13.2.8.11節(jié),“對于較早的MySQL版本,采用聯(lián)合方法重寫子查詢”。
1.8.5.2. SELECT INTO TABLE
MySQL服務器不支持Sybase SQL擴展: SELECT ... INTO TABLE ....。但MySQL服務器支持標準的SQL語法INSERT INTO ... SELECT ...,它基本上相同。請參見13.2.4.1節(jié),“INSERT ... SELECT語法”。
INSERT INTO tbl_temp2 (fld_id) SELECT tbl_temp1.fld_order_id FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;作為備選方式,可以使用SELECT INTO OUTFILE ...或CREATE TABLE ... SELECT。
從5.0版開始,MySQL支持SELECT ... INTO,以及用戶變量。在使用光標和局部變量的存儲程序中也可以使用相同的語法。請參見20.2.9.3節(jié),“SELECT ... INTO語句”。
1.8.5.3. 事務和原子操作
MySQL服務器(3.23至該系列的最高版本,所有4.0版本,以及更高版本)支持采用InnoDB和BDB事務存儲引擎的事務。InnoDB提供了全面的ACID兼容性。請參見第15章:存儲引擎和表類型。
MySQL服務器中的其他非事務性存儲引擎(如MyISAM)遵從不同的數(shù)據(jù)完整性范例,稱之為“原子操作”。按照事務術語,MyISAM表總能高效地工作在AUTOCOMMIT=1模式下。原子操作通常能提供可比較的完整性以及更好的性能。
由于MySQL服務器支持兩種范例,因而你能決定是否利用原子操作的速度更好地服務于你的應用程序,或使用事務特性。該選擇可按表進行。
正如所闡述的那樣,事務性和非事務性表類型之間的權衡主要取決于性能。事務性表對內(nèi)存和磁盤空間的要求更高,CPU開銷也更大。另一方面,多種事務性表類型,如InnoDB,也能提供很多顯著特性。MySQL服務器的模塊化設計允許同時使用不同的存儲引擎,以滿足不同的要求,并在所有情形下,提供最佳性能。
但是,即便使用非事務性MyISAM表,你將如何使用MySQL服務器的特性來保持嚴格的完整性呢?這些特性與事務性表類型相比又如何呢?
1. 如果應用程序采用了特定的編寫方式,依賴于在關鍵情況下能夠調(diào)用ROLLBACK而不是COMMIT,那么事務性類型更方便。使用事務,還能確保未完成的更新或崩潰的活動不被提交到數(shù)據(jù)庫,能為服務器提供自動回滾的機會,并保存你的數(shù)據(jù)庫。
如果使用非事務性表,MySQL服務器幾乎在所有情況下均允許你解決潛在的問題,方式是在更新前進行簡單檢查,并運行檢查數(shù)據(jù)庫一致性的簡單腳本,如果出現(xiàn)不一致性,該腳本能自動修復它或給出告警。注意,僅使用MySQL日志或增加額外日志,通常能完美地更正表,同時不會造成數(shù)據(jù)完整性損失。
2. 在很多情況下,能夠?qū)﹃P鍵的事務更新進行重寫,使之成為“原子”類型。一般而言,所有由事務解決的完整性問題均能用LOCK TABLES或原子更新解決,從而確保了服務器不會自動中斷,后者是事務性數(shù)據(jù)庫系統(tǒng)的常見問題。
3. 為了安全使用MySQL服務器,無論是否使用事務性表,僅需啟用備份和二進制日志功能。這樣,你就能解決使用其他事務性數(shù)據(jù)庫系統(tǒng)時遇到的任何問題。無論使用的數(shù)據(jù)庫系統(tǒng)是什么,啟用備份總是個好主意。
事務范型有自己的優(yōu)點和不足之處。很多用戶和應用程序開發(fā)人員喜歡這類簡單性,在出現(xiàn)問題時或必要時,通過代碼解決問題。但是,即使你是原子操作范型的新手,或更熟悉事務,也請考慮非事務性表的速度益處,與經(jīng)過優(yōu)化調(diào)整的最快的事務性表相比,它的速度快3~5倍。
在完整性具有最高重要性的情況下,即使是對非事務性表,MySQL也能提供事務級別的可靠性和安全性。如果使用LOCK TABLES鎖定了表,所有更新均將被暫時中止直至完整性檢查完成。如果你獲得了對某一表的READ LOCAL鎖定(與寫鎖定相對),該表允許在表尾執(zhí)行并行插入,當其他客戶端執(zhí)行插入操作時,允許執(zhí)行讀操作。新插入的記錄不會被有讀鎖定屬性的客戶端看到,直至解除了該鎖定為止。使用INSERT DELAYED,能夠?qū)⒉迦腠椫糜诒镜仃犃兄,直至鎖定解除,不會讓客戶端等待插入完成。請參見13.2.4.2節(jié),“INSERT DELAYED語法”。
從我們賦與其名稱的意義上,“原子”絕非不可思議的。它僅意味著,你能確信在每個特性更新運行的同時,其他用戶不能干涉它,而且不會出現(xiàn)自動回滾(如果你不小心,對于事務性表,這種情況可能發(fā)生)。MySQL服務器還能保證不存在臟讀。
下面列出了使用非事務性表的一些技術:
· 對于需要事務的循環(huán),通常能使用LOCK TABLES進行編碼,不需要光標來更新正在處理的記錄。
· 要想避免使用ROLLBACK,可采取下述策略:
1. 使用LOCK TABLES鎖定所有希望訪問的表。
2. 執(zhí)行更新前,測試必須為真的條件。
3. 如果一切正常,執(zhí)行更新。
4. 使用UNLOCK TABLES解除鎖定。
與使用具有回滾可能性的事務性表相比,它通常具有更快的速度,雖然并非始終如此。該解決方案唯一不能處理的情形是,在更新中途殺死了線程。在這種情況下,將釋放所有鎖定,但某些更新可能尚未執(zhí)行。
· 也可以使用函數(shù)在單一操作中更新記錄。采用下述技術,能獲得效率很高的應用程序。
o 根據(jù)其當前值更改列。
o 僅更新出現(xiàn)實際變化的列。
例如,當我們更新某些客戶信息時,僅更新已更改的客戶數(shù)據(jù),與原始行相比,僅測試已更改的數(shù)據(jù)或依賴于已更改數(shù)據(jù)的數(shù)據(jù)是否未出現(xiàn)變化。對于已更改數(shù)據(jù)的測試,它是通過UPDATE語句的WHERE子句完成的。如果記錄未更新,將向客戶端發(fā)出消息: “一些你改變的數(shù)據(jù)已被其他用戶更改”。接下來,我們在窗口中給出了舊行和新行,以便用戶決定使用哪個版本。
這給出了與列鎖定類似的結果,但效果更好,使用相對于其當前值的值,僅更新了某些列。這意味著,典型的UPDATE語句與下面給出的類似:
UPDATE tablename SET pay_back=pay_back+125; UPDATE customer SET customer_date='current_date', address='new address', phone='new phone', money_owed_to_us=money_owed_to_us-125 WHERE customer_id=id AND address='old address' AND phone='old phone';它很有效,即使其他客戶端更改了pay_back或money_owed_to_us列中的值,也能使用。
· 在很多情況下,用戶希望將LOCK TABLES和/或ROLLBACK用于管理唯一ID。可以在不使用鎖定功能或回滾的情況下,使用AUTO_INCREMENT列以及LAST_INSERT_ID() SQL函數(shù)或mysql_insert_id() C API函數(shù),更有效地處理之。請參見12.9.3節(jié),“信息函數(shù)”。請參見25.2.3.36節(jié),“mysql_insert_id()”。
我們通常能使用代碼來處理行級鎖定方面的需求。在某些情況下,實際上不需要它,InnoDB表支持行級鎖定。通過MyISAM表,能夠在表中使用標志列,并完成類似下面的操作:
UPDATE tbl_name SET row_flag=1 WHERE id=ID;如果找到行,而且原始行中的row_flag不是1,對于受影響的行數(shù),MySQL返回1。
你可以認為MySQL將前述查詢更改為:
UPDATE tbl_name SET row_flag=1 WHERE id=ID AND row_flag <> 1;1.8.5.4. 存儲程序和觸發(fā)程序
對于MySQL,在5.0版本中實現(xiàn)了存儲程序。請參見第20章:存儲程序和函數(shù)。
從5.0.2版開始,在MySQL中實現(xiàn)了基本的觸發(fā)器功能,計劃在MySQL 5.1中進一步發(fā)展它。請參見第21章:觸發(fā)程序。
1.8.5.5. 外鍵
在MySQL服務器3.23.44和更高版本中,InnoDB存儲引擎支持對外鍵約束的檢查功能,這些約束包括CASCADE、ON DELETE和ON UPDATE。請參見15.2.6.4節(jié),“FOREIGN KEY約束”。
對于InnoDB之外的其他存儲引擎,MySQL服務器能夠解析CREATE TABLE語句中的FOREIGN KEY語法,但不能使用或保存它。未來將進行擴展,能夠?qū)⑦@類信息保存到表規(guī)范文件中,以便能被mysqldump和ODBC檢索。稍后,還將為MyISAM表實現(xiàn)外鍵約束。
外鍵增強為數(shù)據(jù)庫開發(fā)人員提供了多項益處:
· 假定關聯(lián)設計恰當,外鍵約束使得程序員更難將不一致性引入數(shù)據(jù)庫。
· 數(shù)據(jù)庫服務器具有集中式約束檢查功能,因而沒有必要在應用程序一側執(zhí)行這類檢查。這樣,就消除了不同應用程序使用不同方式檢查約束的可能性。
· 使用級聯(lián)更新和刪除,簡化了應用程序代碼。
· 設計恰當?shù)耐怄I有助于以文檔方式記錄表間的關系。
請記住,這些好處是以數(shù)據(jù)庫服務器為執(zhí)行必要檢查而需的額外開銷為代價的。服務器額外檢查會影響性能,對于某些應用程序,該特性不受歡迎,應盡量避免。(出于該原因,在一些主要的商業(yè)應用程序中,在應用程序級別上實施了外鍵邏輯)。
MySQL允許數(shù)據(jù)庫開發(fā)人員選擇要使用的方法。如果你不需要外鍵,并希望避免與強制引用完整性有關的開銷,可選擇另一種表類型取而代之,如MyISAM。(例如,MyISAM存儲引擎為僅執(zhí)行INSERT和SELECT操作的應用程序提供了極快的性能,這是因為插入能和檢索同時進行)。請參見7.3.2節(jié),“表鎖定事宜”。
如果你不打算利用引用完整性檢查具備的優(yōu)點,請記住下述要點:
· 不存在服務器端外鍵關聯(lián)檢查時,應用程序本身必須處理這類關聯(lián)事宜。例如,將行按恰當順序插入表時應謹慎,并應避免產(chǎn)生孤立的子記錄。必須能夠在多記錄插入操作期間更正出現(xiàn)的錯誤。
· 如果ON DELETE是應用程序所需的唯一引用完整性功能,請注意,從MySQL服務器4.0起,可以使用多表DELETE語句,用單一語句從多個表中刪除行。請參見13.2.1節(jié),“DELETE語法”。
· 從具有外鍵的表刪除記錄時,在缺少ON DELETE的情況下,一種解決方式是為應用程序增加恰當?shù)腄ELETE語句。實際上,它與使用外鍵同樣快,而且移植性更好。
注意,使用外鍵在某些情況下會導致問題。
· 外鍵支持能處理很多引用完整性事宜,但仍需要仔細設計鍵的關系,以避免循環(huán)規(guī)則或不正確的級聯(lián)刪除組合。
· DBA需要創(chuàng)建關聯(lián)拓撲,這會使從備份中恢復單獨表變得困難,該類情形并不罕見。(加載依賴其他表的表時,MySQL允許你臨時禁止外鍵檢查,從而降低了該難度)。請參見15.2.6.4節(jié),“FOREIGN KEY約束”。在MySQL 4.1.1以前。重新加載時,mysqldump能夠生成自動利用該性能的轉(zhuǎn)儲文件。
注意,SQL中的外鍵用于檢查和強制引用完整性,而不是聯(lián)合表。如果打算用SELECT語句獲取多個表的結果,可在表之間執(zhí)行聯(lián)合操作:
SELECT * FROM t1, t2 WHERE t1.id = t2.id;請參見13.2.7.1節(jié),“JOIN語法”。請參見3.6.6節(jié),“使用外鍵”。
ODBC應用程序常使用不帶“ON DELETE ...”的FOREIGN KEY語法來生成自動WHERE子句。
1.8.5.6. 視圖
在MySQL服務器5.0版中實現(xiàn)了視圖功能(包括可更新視圖)。在5.0.1和更高版本中,提供了二進制版的視圖功能。請參見第22章:視圖。
View(視圖)十分有用,它允許用戶像單個表那樣訪問一組關系(表),而且僅允許對它們的這類訪問。視圖也能限制對行的訪問(特定表的子集)。對于列控制的訪問,可使用MySQL服務器中的高級權限系統(tǒng)。請參見5.7節(jié),“MySQL訪問權限系統(tǒng)”。
在設計視圖的過程中,我們的宏偉目標是,在SQL的范圍內(nèi)盡可能與關聯(lián)數(shù)據(jù)庫系統(tǒng)的“Codd's Rule #6”兼容。“所有理論上可更新的視圖,實際上也應是可更新的”。
1.8.5.7. ‘--’作為注釋起始標記
一些其他SQL數(shù)據(jù)庫采用“--”作為注釋開始標志。MySQL服務器采用“#”作為注釋起始字符。對于MySQL服務器,也能使用C風格的注釋:/*該處為注釋*/。請參見9.5節(jié),“注釋語法”。
MySQL服務器3.23.3和更高版本支持“--”注釋風格,但要求注釋后面跟1空格(或控制字符,如新行)。之所以要求使用空格,是為了防止與自動生成SQL查詢有關的問題,它采用了類似下面的代碼,其中,自動為“!payment!”插入“payment”的值:
UPDATE account SET credit=credit-!payment!考慮一下,如果“payment”的值為負數(shù)如“-1”時會出現(xiàn)什么情況:
UPDATE account SET credit=credit--1在SQL中“credit--1”是合法的表達式,但是,如果“--1”被解釋為注釋開始,部分表達式將被舍棄。其結果是,表達式的意義與預期的意義完全不同。
UPDATE account SET credit=credit該語句不會對值作任何更改!這表明,允許注釋以“--”開始會產(chǎn)生嚴重后果。
采用MySQL服務器3.23.3和更高版本中的這類注釋方法,“credit--1”實際上很安全。
另一個安全特性是,mysql命令行客戶端將刪除所有以“--”開頭的行。
僅當使用高于3.23.3的MySQL時,下述信息才有意義:
如果有1個文本文件形式的SQL程序,該文件包含“--”注釋,應按下述方式使用replace實用工具,將其轉(zhuǎn)換為使用“#”字符的注釋:
shell> replace " --" " #" < text-file-with-funny-comments.sql \ | mysql db_name而不是通常的:
shell> mysql db_name < text-file-with-funny-comments.sql你也可以編輯注釋文件,將“--”注釋更改為“#”注釋:
shell> replace " --" " #" -- text-file-with-funny-comments.sql使用下述命令將其改回去:
shell> replace " #" " --" -- text-file-with-funny-comments.sql1.8.6. MySQL處理約束的方式
1.8.6.1. PRIMARY KEY和UNIQUE索引約束
1.8.6.2. 對無效數(shù)據(jù)的約束
1.8.6.3. ENUM和SET約束
使用MySQL,你可以使用允許回滾的事務表,以及不允許回滾的非事務表。因此,在MySQL中的約束處理功能與其他DBMS中的略有不同。在非事務性表中插入或更新大量行時,當出現(xiàn)錯誤以至于不能回滾所作的變更時,必須處理該情況。
其基本原理在于,在解析將要執(zhí)行的語句的同時,MySQL服務器會盡量為檢測到的問題生成錯誤信息,并會在執(zhí)行語句的同時盡量恢復出現(xiàn)的錯誤。在大多數(shù)情況下我們均是這樣作的,但不包括所有情況。
出現(xiàn)錯誤時,MySQL可選擇中途中止語句,或盡可能恢復并繼續(xù)執(zhí)行語句。默認情況下,服務器將采取后一種路線。這意味著,服務器可能會強制將非法值變?yōu)樽罱咏暮戏ㄖ担ɡ纾?br />
從MySQL 5.0.2開始,提供了數(shù)種SQL模式,使用它們,能夠?qū)θ绾谓邮芸赡転椴涣紨?shù)據(jù)值的方式進行更好的控制,也能在出現(xiàn)錯誤時,對是否繼續(xù)執(zhí)行語句或放棄語句進行控制。使用這些選項,能夠?qū)ySQL服務器配置為更為傳統(tǒng)的風格,類似于拒絕不恰當輸入的其他DBMS?梢栽谶\行時設置SQL模式,這樣,各客戶端就能選擇與其需求最為貼切的行為。請參見5.3.2節(jié),“SQL服務器模式”。
在以下部分,介紹了使用不同約束類型的情況。
1.8.6.1. PRIMARY KEY和UNIQUE索引約束
通常情況下,當你試圖INSERT或UPDATE會導致主鍵、唯一鍵或外鍵沖突的行時,將出現(xiàn)錯誤。如果你正在使用事務性存儲引擎時,如InnoDB,MySQL會自動回滾語句。如果你正在使用非事務性存儲引擎,MySQL將在出錯的行上停止執(zhí)行語句,剩余的行也不再處理。
如果你希望忽略這類鍵沖突,可使用MySQL支持的、用于INSERT和UPDATE的IGNORE關鍵字。在這種情況下,MySQL將忽略任何鍵沖突,并繼續(xù)處理下一行。請參見13.2.4節(jié),“INSERT語法”。請參見3.2.10節(jié),“UPDATE語法”。
使用mysql_info() C API函數(shù),能夠獲取關于實際插入或更新行數(shù)的信息。請參見25.2.3.34節(jié),“mysql_info()”。在MySQL 4.1和更高版本中,也能使用SHOW WARNINGS語句。請參見13.5.4.22節(jié),“SHOW WARNINGS語法”。
目前,只有InnoDB表支持外鍵。請參見15.2.6.4節(jié),“FOREIGN KEY約束”。計劃在MySQL 5.1中實施對MyISAM表的外鍵支持。
1.8.6.2. 對無效數(shù)據(jù)的約束
在MySQL 5.0.2之前,MySQL對非法或不當值并不嚴厲,而且為了數(shù)據(jù)輸入還會強制將它們變?yōu)楹戏ㄖ怠T贛ySQL 5.0.2和更高版本中,保留了以前的默認行為,但你可以為不良值選擇更傳統(tǒng)的處理方法,從而使得服務器能夠拒絕并放棄出現(xiàn)不良值的語句。本節(jié)介紹了MySQL的默認行為(寬大行為),新的嚴格的SQL模式,以及它們的區(qū)別。
如果你未使用嚴格模式,下述情況是真實的。如果將“不正確”的值插入到列,如將NULL值插入非NULL列,或?qū)⑦^大的數(shù)值插入數(shù)值列,MySQL會將這些列設置為“最可能的值”,而不是生成錯誤信息。
· 如果試圖將超范圍的值保存到數(shù)值列,MySQL服務器將保存0(最小的可能值)取而代之,或最大的可能值。
· 對于字符串,MySQL或保存空字符串,或?qū)⒆址M可能多的部分保存到列中。
· 如果打算將不是以數(shù)值開頭的字符串保存到數(shù)值列,MySQL將保存0。
· MySQL允許將特定的不正確日期值保存到DATE和DATETIME列(如“2000-02-31”或“2000-02-00”)。其觀點在于,驗證日期不是SQL服務器的任務。如果MySQL能保存日期值并準確檢索相同的值,MySQL就能按給定的值保存它。如果日期完全不正確(超出服務器能保存的范圍)將在列中保存特殊的日期值“0000-00-00”取而代之。
· 如果試圖將NULL值保存到不接受NULL值的列,對于單行INSERT語句,將出現(xiàn)錯誤。對于多行INSERT語句或INSERT INTO ... SELECT語句,MySQL服務器會保存針對列數(shù)據(jù)類型的隱含默認值。一般情況下,對于數(shù)值類型,它是0,對于字符串類型,它是空字符串(''),對于日期和時間類型是“zero”。在13.1.5節(jié),“CREATE TABLE語法”一節(jié)中,討論了隱含的默認值。
· 如果INSERT語句未為列指定值,如果列定義包含明確的DEFAULT子句,MySQL將插入默認值。如果在定義中沒有這類DEFAULT子句,MySQL會插入列數(shù)據(jù)類型的隱含默認值。
采用前述規(guī)則的原因在于,在語句開始執(zhí)行前,無法檢查這些狀況。如果在更新了數(shù)行后遇到這類問題,我們不能僅靠回滾解決,這是因為存儲引擎可能不支持回滾。中止語句并不是良好的選擇,在該情況下,更新完成了“一半”,這或許是最差的情況。對于本例,較好的方法是“僅可能做到最好”,然后就像什么都未發(fā)生那樣繼續(xù)。
在MySQL 5.0.2和更高版本中,可以使用STRICT_TRANS_TABLES或STRICT_ALL_TABLES SQL模式,選擇更嚴格的處理方式。請參見5.3.2節(jié),“SQL服務器模式”。
STRICT_TRANS_TABLES的工作方式:
· 對于事務性存儲引擎,在語句中任何地方出現(xiàn)的不良數(shù)據(jù)值均會導致放棄語句并執(zhí)行回滾。
· 對于非事務性存儲引擎,如果錯誤出現(xiàn)在要插入或更新的第1行,將放棄語句。(在這種情況下,可以認為語句未改變表,就像事務表一樣)。首行后出現(xiàn)的錯誤不會導致放棄語句。取而代之的是,將調(diào)整不良數(shù)據(jù)值,并給出告警,而不是錯誤。換句話講,使用STRICT_TRANS_TABLES后,錯誤值會導致MySQL執(zhí)行回滾操作,如果可以,所有更新到此為止。
要想執(zhí)行更嚴格的檢查,請啟用STRICT_ALL_TABLES。除了非事務性存儲引擎,它與STRICT_TRANS_TABLES等同,即使當不良數(shù)據(jù)出現(xiàn)在首行后的其他行,所產(chǎn)生的錯誤也會導致放棄語句。這意味著,如果錯誤出現(xiàn)在非事務性表多行插入或更新過程的中途,僅更新部分結果。前面的行將完成插入或更新,但錯誤出現(xiàn)點后面的行則不然。對于非事務性表,為了避免這種情況的發(fā)生,可使用單行語句,或者在能接受轉(zhuǎn)換警告而不是錯誤的情況下使用STRICT_TRANS_TABLES。要想在第1場合防止問題的出現(xiàn),不要使用MySQL來檢查列的內(nèi)容。最安全的方式(通常也較快)是,讓應用程序負責,僅將有效值傳遞給數(shù)據(jù)庫。
有了嚴格的模式選項后,可使用INSERT IGNORE或UPDATE IGNORE而不是不帶IGNORE的INSERT或UPDATE,將錯誤當作告警對待。
1.8.6.3. ENUM和SET約束
ENUM和SET列提供了定義僅能包含給定值集合的列的有效方式。但是,從MySQL 5.0.2起,ENUM和SET不是實際約束。其原因與不重視NOT NULL的原因一樣。請參見1.8.6.2節(jié),“對無效數(shù)據(jù)的約束”。
ENUM列總有1個默認值。如果未指定默認值,對于包含NULL的列,默認值為NULL;否則,第1個枚舉值將被當作默認值。
如果在ENUM列中插入了不正確的值,或者,如果使用IGNORE將值強制插入了ENUM列,會將其設置為保留的枚舉值0,對于字符串情形,將顯示為空字符串。請參見11.4.4節(jié),“ENUM類型”。
如果在SET列中插入了不正確值,該值將被忽略。例如,如果列能包含值“a”、“b”和“c”,并賦值“a,x,b,y”,結果為“a,b”。請參見11.4.5節(jié),“SET類型”。
從5.0.2開始,可以對服務器進行配置,以使用嚴格的SQL模式。請參見5.3.2節(jié),“SQL服務器模式”。啟用嚴格模式后,ENUM或SET列的定義可作為對輸入至列的值的約束。如果值不滿足下述條件,將出現(xiàn)錯誤:
· ENUM值必須是在列定義中給出的值之一,或內(nèi)部的數(shù)字等同物。該值不能是錯誤值(即,0或空字符串)。對于定義為ENUM('a','b','c')的列,諸如''、'd'和'ax'等,均是非法的,并將被拒。
· SET值必須是空字符串,或由1個或多個在列定義中給出的且用逗號隔開的值組成。 對于定義為SET('a','b','c')的列,諸如'd'和'a,b,c,d'等,均是非法的,并將被拒。
如果使用了INSERT IGNORE或UPDATE IGNORE,在嚴格模式下,可抑制無效值導致的錯誤。在這種情況下,將生成警告而不是錯誤。對于ENUM,值將作為錯誤成員(0)插入。對于SET,會將給定值插入,但無效的子字符串將被刪除。例如,'a,x,b,y'的結果是'a,b',就像前面介紹的那樣。 |
|