錯誤處理與查詢

1 錯誤的資料

在規劃與設計一個資料庫的時候,你會針對儲存資料的需求,定義每一個表格中的欄位,包含欄位的資料型態與其它的設定,這些定義都會影響資料的查詢與維護。資料庫中儲存的資料應該是正確而且沒有誤差的,如果你嘗試儲存一個錯誤的資料,資料庫應該要發現問題並告訴你不可以這樣做;不過在不同的需求下,你可能會希望資料庫允許不太嚴重的錯誤,不要每次都產生錯誤訊息。

MySQL資料庫環境中,可以使用「sql_mode」系統變數設定資料庫對於檢查錯誤資料的「嚴格」程度,分為「strict」與「non-strict」兩種模式。在strict模式下,資料庫會嚴格的檢查與發現錯誤的資料,而且不會儲存錯誤的資料;在non-strict模式下,資料庫同樣會檢查與發現錯誤的資料,不過它會儘量試著處理這些錯誤的資料,再把資料儲存起來。

你可以依照自己的需求設定「sql_mode」系統變數,下列的指令可以設定為「non-strict」模式:

下列的敘述設定為「strict」模式:

「STRICT_TRANS_TABLES」與「STRICT_ALL_TABLES」同樣可以設定為「strict」模式,在使用支援「交易、transaction」的資料庫,應該要設定為「STRICT_TRANS_TABLES」,這樣可以確定資料的完整性。

設定為「strict」與「non-strict」兩種不同的模式,對於錯誤資料的處理會有很大的差異。下列是一個用來測試的表格「cmdev.debug」,它包含許多不同資料型態與設定的欄位:

欄位名稱 型態 NULL 索引 預設值 其它資訊
fint tinyint(4) NO NULL
fchar varchar(3) YES NULL
fdouble double(5, 2) YES NULL
fdate date YES NULL
ftime time YES NULL
fenum enum(‘A’,'B’,'C’) YES NULL
fset set(‘A’,'B’,'C’) YES NULL

2 Non-Strict模式

下列是使用「SET」設定「sql_mode」變數的語法:

如果沒有指定「SESSION」或「GLOBAL」的話,MySQL會把這個設定當成「SESSION」,設定的效果只有一個用戶端的連線,並不會影響其它用戶端連線的設定。下列的範例設定為「non-strict」模式後,使用「SHOW」或「SELECT」敘述查詢設定後的結果:

如果你希望將所有用戶端都設定為「non-strict」模式,那就要使用「GLOBAL」關鍵字:

設定為「non-strict」模式以後,在執行資料維護時,如果資料完全符合欄位資料型態的規定,那就不會發生任何警告或錯誤:

如果資料庫發現不符合欄位規定的資料,它會儘量試著處理這些錯誤的資料,再把資料儲存起來。以下列的範例來說,想要儲存到字串型態欄位的值有六個字元,可是「fchar」欄位只能儲存三個字元,資料庫在「non-strict」模式下,會忽略多餘的字元後再儲存起來,然後使用警告訊息通知你:

在non-strict模式運作時,下列幾種情形都有可能會啟動自動修正資料的功能:

  • 執行新增或修改敘述,包含INSERT、REPLACE、UPDATE與LOAD DATA INFILE

  • 使用ALTER TABLE修改表格的欄位定義

  • 在欄位定義中使用「DEFAULT」指定欄位的預設值

註:「LOAD DATA INFILE」在「匯入與匯出資料、使用SQL敘述匯入資料」中討論。

2.1 數值

資料庫在「non-strict」模式下,處理數值資料型態會使用比較寬鬆的方式。以整數型態「TINYINT」來說,如果儲存的數值超過規定的範圍,資料庫會依照下列的方式來處理錯誤的數值資料:

浮點數型態與整數型態一樣有規定的範圍,如果你在定義浮點數型態欄位時,也設定了長度與小數位數,那就只能儲存設定的範圍:

註:儲存小數到整數型態的欄位,或是小數位數超過浮點數型態定義的位數,MySQL會針對小數的部份執行四捨五入,並不會有任何錯誤或警告。

2.2 列舉(ENUM)與集合(SET)

「ENUM」型態只能儲存一個規定好的成員資料,以「fenum」欄位來說,它設定了A、B、C三個成員,你也可以使用數值1、2、3表示。在「non-strict」模式下,如果你嘗試儲存錯誤的資料,資料庫都會儲存空的字串「"」,數值為0:

「SET」型態可以儲存一組規定好的成員資料,以以「fset」欄位來說,它設定了X、Y、Z三個成員。在「non-strict」模式下,如果你嘗試儲存錯誤的資料,資料庫都會儲存空的字串「"」,數值為0;如果指定的成員不正確的話,資料庫也會自動忽略它們:

註:重複的集合成員不會造成任何錯誤或警告。例如儲存「’X,X,Y,Y,Z,Z’」的值到「fset」欄位,實際儲存的是「’X,Y,Z’」。

2.3 字串轉換為其它型態

資料庫設定為「non-strict」模式的時候,如果你想要儲存字串資料到非字串型態的欄位,資料庫都會幫你轉換為欄位的型態後再儲存。如果字串的內容不能轉換為欄位的型態,例如想要儲存字串「Hello!」到數值型態欄位,資料庫會儲存下列的預設值,然後產生警告訊息:

欄位型態 預設值 欄位型態 預設值
數值 0 TIMESTAMP ’0000-00-00 00:00:00′
DATE ’0000-00-00′ YEAR 0000或00
TIME ’00:00:00′ ENUM
DATETIME ’0000-00-00 00:00:00′ SET

在執行字串轉換型態的時候,資料庫會使用很寬鬆的方式,盡量把你的資料儲存起來,尤其是字串轉換為數值與日期型態:

字串值 fint fdate
’10-10-10′ 10 ’2010-10-10′
’007′ 7 ’0000-00-00′
‘SAM36′ 0 ’0000-00-00′
’36SAM’ 36 ’0000-00-00′
’25-SAM’ 25 ’0000-00-00′
’12 SAM’ 12 ’0000-00-00′
‘SAM’ 0 ’0000-00-00′

2.4 NULL與NOT NULL

在規劃表格欄位的時候,你會根據需求設定欄位是否可以儲存「NULL」值。如果你設定某一個欄位不可以儲存「NULL」值,不論在「non-strict」或「strict」模式下,儲存「NULL」值的敘述都會發生錯誤訊息:

資料庫設定為「non-strict」模式的時候,下列的情況只會產生警告訊息:

2.5 Strict模式與IGNORE關鍵字

你也可以將資料庫設定為「strict」模式,在這個模式下,只有在儲存字串資料到非字串型態的欄位時,資料庫會嘗試幫你指定的字串轉換為欄位型態;其它任何違反資料型態的問題,資料庫不會儲存錯誤的資料,而且會產生錯誤訊息。

在「strict」模式模式下執行新增與修改時,可以依照需求加入「IGNORE」關鍵字:

3 其它設定

「sql_mode」變數設定為「non-strict」或「strict」模式後,還可以依照自己的需求加入額外的設定:

設定值 說明
ALLOW_INVALID_DATES 允許錯誤的日期資料
NO_ZERO_DATE 不允許全部是0的日期資料
NO_ZERO_IN_DATE 日期資料中不可以有0
ERROR_FOR_DIVISION_BY_ZERO 除以0時產生錯誤,而不是產生NULL值

如果你希望資料庫設定為「strict」模式,可是對於日期資料的檢查又可以寬鬆一些,你可以執行下列的設定:

加入「ALLOW_INVALID_DATES」的設定以後,就算是「2000-02-31」這樣一個錯誤的日期資料,資料庫也會儲存它,不會有任何警告或錯誤訊息:

日期型態的欄位,不論在「non-strict」或「strict」模式下,你都可以儲存年月日為0的日期資料,不會產生任何警告或錯誤訊息。如果不希望儲存這樣的日期資料,你可以加入「NO_ZERO_DATE」與「NO_ZERO_IN_DATE」的設定:

如果在你執行的敘述中出現除以零的運算式,資料庫會產生「NULL」值,並不會產生任何警告或錯誤訊息。你可以加入「ERROR_FOR_DIVISION_BY_ZERO」設定:

在敘述中出現除以零的運算式時,資料庫會產生除以零的錯誤訊息:

你可以使用不同的設定項目,讓資料庫中的資料更符合自己的需求。MySQL也為你準備了許多不同的設定組合,讓你可以方便的完成「sql_mode」的設定:

設定值 設定項目
ANSI REAL_AS_FLOAT、PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE
DB2 PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、 NO_TABLE_OPTIONS、NO_FIELD_OPTIONS
MAXDB PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、 NO_TABLE_OPTIONS、NO_FIELD_OPTIONS、NO_AUTO_CREATE_USER
MSSQL PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、 NO_TABLE_OPTIONS、NO_FIELD_OPTIONS
MYSQL323 NO_FIELD_OPTIONS、HIGH_NOT_PRECEDENCE
MYSQL40 NO_FIELD_OPTIONS、HIGH_NOT_PRECEDENCE
ORACLE PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、 NO_TABLE_OPTIONS、NO_FIELD_OPTIONS、NO_AUTO_CREATE_USER
POSTGRESQL PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、 NO_TABLE_OPTIONS、NO_FIELD_OPTIONS
TRADITIONAL STRICT_TRANS_TABLES、STRICT_ALL_TABLES、NO_ZERO_IN_DATE、NO_ZERO_DATE、ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER

註:「sql_mode」的完整設定可以參考MySQL參考手冊中的「5.2.6. SQL Modes」。

4 查詢錯誤與警告

在執行SQL敘述後,如果發生警告或錯誤,你可能需要根據這些訊息來執行一些補救工作。MySQL提供的「SHOW」指令可以查詢這些訊息:

以下列的新增敘述來說,在「non-strict」模式下,雖然會新增一筆紀錄到「debug」表格中,不過想要儲存的三個資料都是有問題的:

執行上列的新增敘述後,你可以使用「SHOW WARNINGS」查詢所有的問題:

下列這個刪除表格的敘述,因為使用了「IF EXISTS」,可以預防因為要刪除的表格不存在而產生錯誤,所以執行敘述以後,指會產生一個「Note」告訴你要刪除的表格不存在:

如果查詢敘述中指定的欄位不存在的話,就會產生錯誤訊息,在執行敘述以後,可以使用「SHOW ERRORS」查詢發生了哪些錯誤:

如果是因為執行SQL敘述,導致資料庫產生的警告或錯誤,都可以使用「SHOW WARNINGS」或「SHOW ERRORS」查詢;不過也有可能是因為作業系統發生問題,例如下列執行匯出資料的敘述,執行敘述以後,資料庫應該建立一個「C:\hello\mydata.sql」檔案,不過因為指定的資料夾並不存在,所以會產生錯誤訊息:

如果發生這類的錯誤,資料庫只會告訴你不能儲存檔案,詳細的錯誤訊息要在命令提示字元下,使用「perror」程式來查詢:

註:匯出資料會在「匯入與匯出資料」中詳細討論。

如果需要知道警告或錯誤的數量,可以使用下列的查詢敘述:

results matching ""

    No results matching ""