BEFORE觸發器修正資料錯誤
昨天嘗試使用BEFORE觸發器記錄或修正匯入過程中出現的資料型別超長的錯誤,結果沒成功,這裡研究一下這個問題。
獲取導致匯入失敗的資料http://yangtingkun.itpub.net/post/468/461401
首先建立測試用表:
SQL> CREATE TABLE T_IMP (ID NUMBER, NAME VARCHAR2(30));
表已建立。
SQL> INSERT INTO T_IMP VALUES (1, 'A');
已建立 1 行。
SQL> INSERT INTO T_IMP VALUES (2, 'B');
已建立 1 行。
SQL> INSERT INTO T_IMP VALUES (1000, 'C');
已建立 1 行。
SQL> INSERT INTO T_IMP VALUES (3, 'D');
已建立 1 行。
SQL> COMMIT;
提交完成。
下面匯出資料:
E:\>EXP YANGTK/YANGTK FILE=T_IMP.DMP TABLES=T_IMP
Export: Release 9.2.0.4.0 - Production on 星期四 5月 8 23:28:26 2008
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
連線到: Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production
已匯出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集
即將匯出指定的表透過常規路徑 ...
. . 正在匯出表 T_IMP 4 行被匯出
在沒有警告的情況下成功終止匯出。
為了構造錯誤,下面清空表的資料,並修改表中ID列的精度,使得剛才匯出的資料無法成功的匯入:
SQL> TRUNCATE TABLE T_IMP;
表被截斷。
SQL> ALTER TABLE T_IMP MODIFY ID NUMBER(3);
表已更改。
下面執行匯入操作:
E:\>IMP YANGTK/YANGTK FILE=T_IMP.DMP TABLES=T_IMP IGNORE=Y
Import: Release 9.2.0.4.0 - Production on 星期四 5月 8 23:30:05 2008
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
連線到: Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production
經由常規路徑匯出由EXPORT:V09.02.00建立的檔案
已經完成ZHS16GBK字符集和AL16UTF16 NCHAR 字符集中的匯入
. 正在將YANGTK的物件匯入到 YANGTK
. . 正在匯入表 "T_IMP"
IMP-00058: 遇到 ORACLE 錯誤 1438
ORA-01438: 值大於此列指定的允許精確度
IMP-00028: 上一個表的部分匯入已回退: 回退 2 行
成功終止匯入,但出現警告。
錯誤已經重現,下面可以建立日誌表和BEFORE觸發器了:
SQL> CREATE TABLE T_IMP_BAK (ID NUMBER, NAME VARCHAR2(30));
表已建立。
SQL> CREATE OR REPLACE TRIGGER T_IMP
2 BEFORE INSERT ON T_IMP
3 FOR EACH ROW
4 DECLARE
5 PRAGMA AUTONOMOUS_TRANSACTION;
6 BEGIN
7 INSERT INTO T_IMP_BAK VALUES (:NEW.ID, :NEW.NAME);
8 COMMIT;
9 END;
10 /
觸發器已建立
建立BEFORE觸發器,且設定觸發器為自治事務,是為了在錯誤發生之前,將導致錯誤產生的資料插入到日誌表中,且插入的記錄不會隨著匯入的失敗而回滾。
再次執行匯入操作:
E:\>IMP YANGTK/YANGTK FILE=T_IMP.DMP TABLES=T_IMP IGNORE=Y
Import: Release 9.2.0.4.0 - Production on 星期四 5月 8 23:33:30 2008
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
連線到: Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production
經由常規路徑匯出由EXPORT:V09.02.00建立的檔案
已經完成ZHS16GBK字符集和AL16UTF16 NCHAR 字符集中的匯入
. 正在將YANGTK的物件匯入到 YANGTK
. . 正在匯入表 "T_IMP"
IMP-00058: 遇到 ORACLE 錯誤 1438
ORA-01438: 值大於此列指定的允許精確度
IMP-00028: 上一個表的部分匯入已回退: 回退 2 行
成功終止匯入,但出現警告。
檢查日誌表的記錄:
SQL> SELECT * FROM T_IMP_BAK;
ID NAME
---------- ------------------------------
1 A
2 B
發現預期的導致錯誤發生的記錄並未寫入到日誌表中。
導致這種情況出現的可能性有很多中,比如BEFORE觸發器並不是想象中的那樣真的在插入之前觸發;IMP工具的特殊性導致自治事務也被回滾;錯誤並非發生在插入過程中,而是發生在插入之前;Oracle的bug導致的問題等等。
下面繼續驗證到底是何種原因導致了當前的問題:
SQL> CREATE OR REPLACE TRIGGER T_IMP
2 BEFORE INSERT ON T_IMP
3 FOR EACH ROW
4 DECLARE
5 PRAGMA AUTONOMOUS_TRANSACTION;
6 BEGIN
7 INSERT INTO T_IMP_BAK VALUES (:NEW.ID, :NEW.NAME);
8 COMMIT;
9 IF :NEW.ID > 999 THEN
10 :NEW.ID := 999;
11 END IF;
12 END;
13 /
觸發器已建立
SQL> INSERT INTO T_IMP VALUES (1000, 'C');
INSERT INTO T_IMP VALUES (1000, 'C')
*
第 1 行出現錯誤:
ORA-01438: 值大於此列指定的允許精確度
修改觸發器,在插入日誌後,修改要插入到目標表的值,使得超過精度限制的資料縮小到可以正常插入的範圍內,並嘗試使用SQL語句來執行插入操作。
結果發現,錯誤依舊。難道這個錯誤的產生真的不是在插入的時候,而是在插入之前就會數值進行了判斷。
嘗試修改列的精度,使得插入資料的原值可以順利插入:
SQL> ALTER TABLE T_IMP MODIFY ID NUMBER(4);
表已更改。
SQL> INSERT INTO T_IMP VALUES (1000, 'C');
已建立 1 行。
SQL> SELECT * FROM T_IMP;
ID NAME
---------- ------------------------------
999 C
SQL> SELECT * FROM T_IMP_BAK;
ID NAME
---------- ------------------------------
1 A
2 B
1000 C
現在已經可以確定,Oracle會先判斷修改的值是否滿足表欄位的精度設定,然後才會呼叫BEFORE觸發器,接著就是SQL語句本身的執行,最後呼叫AFTER觸發器。
看來利用BEFORE觸發器修改超過表欄位精度的資料來實現資料正常匯入的方式是行不通的。BEFORE觸發器的修改只能針對那些本身就滿足欄位限制的資料。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-263399/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Linux 時間錯誤的修正Linux
- 除錯觸發器除錯觸發器
- 修正FIREFOX下批量上傳的錯誤Firefox
- 修正memcache.php中的錯誤示例PHP
- mysql觸發器案例分析以及before和after的區別MySql觸發器
- 通過觸發器尋找密碼錯誤使用者觸發器密碼
- 資料庫檢視,索引,觸發器資料庫索引觸發器
- 資料庫的觸發器的使用資料庫觸發器
- PAT A1104測試點2錯誤修正方法
- 修正織夢CMS的RSS檔案的URL錯誤
- mysql 觸發器SQLSTATE[42S22] 'now.order_no' in 'field list' 的錯誤MySql觸發器
- 觸發器實現表資料自動更新觸發器
- 解決 windows遠端桌面報錯“CredSSP加密資料庫修正”Windows加密資料庫
- 2018-05-21 修正cordova開發報錯
- mysql資料庫伺服器錯誤怎麼回事MySql資料庫伺服器
- 通過觸發器記錄資料庫連線資訊觸發器資料庫
- MySQL建立觸發器時報錯Error Code: 1064MySql觸發器Error
- SAP 資料更新的觸發
- ORA-01653錯誤是Oracle資料庫中常見的錯誤Oracle資料庫
- 假資料填充錯誤記錄
- mysql觸發器MySql觸發器
- D觸發器觸發器
- 頭歌資料庫實驗七:函式與觸發器資料庫函式觸發器
- 解決 PBootCMS 中因資料庫名稱錯誤導致的“執行 SQL 發生錯誤!錯誤:no such table: ay_config”問題boot資料庫SQL
- SQL Server DACPAC資料庫部署錯誤SQLServer資料庫
- SqlServer-觸發器SQLServer觸發器
- logon觸發器for dbaGo觸發器
- MySQL使用觸發器MySql觸發器
- 語句觸發器觸發器
- MySql-觸發器MySql觸發器
- sqlserver 列觸發器SQLServer觸發器
- 建立MySQL觸發器MySql觸發器
- PbootCMS錯誤提示:執行SQL發生錯誤!錯誤:no such column: def1bootSQL
- Error infos:DedeCms錯誤警告:連線資料庫失敗,可能資料庫密碼不對或資料庫伺服器出錯!Error資料庫密碼伺服器
- Error infos: DedeCms錯誤警告:連線資料庫失敗,可能資料庫密碼不對或資料庫伺服器出錯!Error資料庫密碼伺服器
- php 對空陣列元素??並進行運算,可能觸發 Undefined index 錯誤PHP陣列UndefinedIndex
- postfix 發信錯誤
- 網站連線資料庫配置錯誤網站資料庫
- 網站提示資料庫連線錯誤網站資料庫