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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 用觸發器返回錯誤提示,糾正錯誤資料錄入觸發器
- 除錯觸發器除錯觸發器
- SQL Server中類似Oracle中before觸發器SQLServerOracle觸發器
- Linux 時間錯誤的修正Linux
- 修正windows下ora錯誤顯示???Windows
- 通過觸發器尋找密碼錯誤使用者觸發器密碼
- Oracle goldengate的觸發器錯誤 OGG-00869OracleGo觸發器
- mysql觸發器案例分析以及before和after的區別MySql觸發器
- 學習before之:new或:old轉化加工觸發器觸發器
- 修正memcache.php中的錯誤示例PHP
- 資料庫開發---常用物件-觸發器資料庫物件觸發器
- 資料庫觸發器,禁止DDL操作資料庫觸發器
- SQL資料庫觸發器例項SQL資料庫觸發器
- 修正FIREFOX下批量上傳的錯誤Firefox
- Oracle資料庫DDL審計觸發器觸發的bug問題Oracle資料庫觸發器
- SQL Server資料庫級別觸發器SQLServer資料庫觸發器
- Linux 2.6核心bug成災 恐暫停開發修正錯誤(轉)Linux
- mysql 觸發器SQLSTATE[42S22] 'now.order_no' in 'field list' 的錯誤MySql觸發器
- 觸發器實現表資料自動更新觸發器
- 審計資料庫登陸登出觸發器資料庫觸發器
- Jive論壇資料庫指令碼沒有安裝。請按照安裝文件修正此錯誤。資料庫指令碼
- oracle 觸發器實現禁止在資料庫中建立dblink ---透過觸發器實現Oracle觸發器資料庫
- 觸發器限制指定IP訪問oracle資料庫觸發器Oracle資料庫
- oracle巧用觸發器提高資料庫安全級別Oracle觸發器資料庫
- 審計資料庫登陸失敗觸發器資料庫觸發器
- Oracle觸發器觸發級別Oracle觸發器
- 通過觸發器記錄資料庫連線資訊觸發器資料庫
- 匯入大容量資料時控制觸發器執行觸發器
- ORACLE表資料觸發器,僅保留一天的實時資料Oracle觸發器
- SAP 資料更新的觸發
- WPS中活用查詢替換修正OCR識別錯誤
- Oracle觸發器6(建立系統事件觸發器)Oracle觸發器事件
- 根據業務寫觸發器(oracle觸發器片)觸發器Oracle
- RAC中誤將資料檔案建立在本地盤時的修正
- 【問題處理】以SYSOPER許可權登入資料庫觸發ORA-01075錯誤資料庫
- MySQL觸發器MySql觸發器
- mysql——觸發器MySql觸發器
- mysql 觸發器MySql觸發器