上一篇簡單介紹了DML記錄語句的限制,雖然所有的例子都是利用INSERT語句,但是LOG ERRORS語句並沒有這個限制,UPDATE、DELETE和MERGE都可以使用這個語句。下面要說的就是這篇的重點,LOG ERRORS語句的限制。
不支持的操作:
違反延遲約束;
直接路徑的INSERT或MERGE語句違反了唯一約束或唯一索引;
更新操作違反了唯一約束或唯一索引。
不支持的數據類型:
比如:LONG、LONG RAW、BLOG、CLOB、NCLOB、BFILE以及各種對象類型。Oracle不支持這些類型的原因也很簡單,這些特殊的類型不是包含了大量的記錄,就是需要通過特殊的方法來讀取,因此Oracle沒有辦法在SQL處理的時候將對應列的信息寫到錯誤記錄表中。
1.下面我們來看不支持的操作,首先看一下違反延遲約束,
SQL> ALTER TABLE T1 ADD CONSTRAINT PK_T1_B CHECK (B IS NOT NULL) DEFERRABLE INITIALLY DEFERRED;
Table altered
測試語句:
SQL> INSERT INTO T1 VALUES('21','') LOG ERRORS INTO ERR_T1('ERR_T1')REJECT LIMIT UNLIMITED;
1 row inserted
SQL> commit;
commit
ORA-02091: 事務處理已回退
ORA-02290: 違反檢查約束條件 (NREI.PK_T1_B)
由於延遲約束的檢查在COMMIT時刻進行,而不是在DML發生的時刻,因此不會利用LOG ERRORS語句將違反結果的記錄插入到記錄表中,這也是很容易理解的。
下面看看直接路徑插入違反唯一約束的情況:
SQL> INSERT /*+ APPEND */ INTO T1 SELECT * FROM T2 LOG ERRORS INTO ERR_T1('ERR_T1')REJECT LIMIT UNLIMITED;
INSERT /*+ APPEND */ INTO T1 SELECT * FROM T2 LOG ERRORS INTO ERR_T1('ERR_T1')REJECT LIMIT UNLIMITED
ORA-00001: 違反唯一約束條件 (NREI.PK_T1_A)
直接路徑插入本身就很特殊,在執行過程中會繞過很多常規SQL執行的步驟,因此LOG ERRORS語句對其無效也是可以理解的。
最后來看看更新語句違反唯一約束的情況:
SQL> UPDATE T1 SET A='1' WHERE A='2' LOG ERRORS INTO ERR_T1('ERR_T1')REJECT LIMIT UNLIMITED;UPDATE T1 SET A='1' WHERE A='2' LOG ERRORS INTO ERR_T1('ERR_T1')REJECT LIMIT UNLIMITED
ORA-00001: 違反唯一約束條件 (NREI.PK_T1_A)
可以看到,如果更新操作導致了唯一約束或唯一索引沖突,也是不會記錄到錯誤記錄表中的。至於為什么更新操作會產生這種情況,還沒有想明白,不過主鍵的沖突和其他約束沖突有所區別,Oracle在處理的時候很可能會有所考慮。
2.下面我們來看不支持的數據類型
SQL> DROP TABLE ERR_T1 PURGE;
Table dropped
SQL> alter table T1 add c clob;
Table altered
SQL> EXEC DBMS_ERRLOG.CREATE_ERROR_LOG('T1','ERR_T1','NREI');
begin DBMS_ERRLOG.CREATE_ERROR_LOG('T1','ERR_T1','NREI'); end;
ORA-20069: Unsupported column type(s) found: C
ORA-06512: 在 "SYS.DBMS_ERRLOG", line 234
ORA-06512: 在 line 1
可以看到,由於T1表擁有不支持的列,導致創建錯誤記錄表的過程報錯,錯誤提示就是T1表中包含了不支持的列。
如果手工添加CLOB字段到錯誤記錄表:
SQL> alter table T1 DROP (c);
Table altered
SQL> EXEC DBMS_ERRLOG.CREATE_ERROR_LOG('T1','ERR_T1','NREI');
PL/SQL procedure successfully completed
SQL> alter table T1 add c clob;
Table altered
SQL> alter table ERR_T1 add c clob;
Table altered
執行插入語句:
SQL> INSERT INTO T1 VALUES('21','21','TEST') LOG ERRORS INTO ERR_T1('ERR_T1')REJECT LIMIT UNLIMITED;
INSERT INTO T1 VALUES('21','21','TEST') LOG ERRORS INTO ERR_T1('ERR_T1')REJECT LIMIT UNLIMITED
ORA-38904: LOB 列 "C" 不支持 DML 錯誤事件記錄
可以看到,Oracle會直接報錯。
SQL> UPDATE T1 SET A='22' WHERE A='2' LOG ERRORS INTO ERR_T1('ERR_T1')REJECT LIMIT UNLIMITED;
UPDATE T1 SET A='22' WHERE A='2' LOG ERRORS INTO ERR_T1('ERR_T1')REJECT LIMIT UNLIMITED
ORA-38904: LOB 列 "C" 不支持 DML 錯誤事件記錄
而Oracle的DML並不包含不支持列的數據,Oracle也會報錯,說明Oracle是在執行之前檢查了錯誤記錄表的數據類型,而不是在執行的時候才去處理。
SQL> alter table ERR_T1 DROP (c);
Table altered
SQL> INSERT INTO T1 VALUES('1','1','TEST' ) LOG ERRORS INTO ERR_T1('ERR_T1')REJECT LIMIT UNLIMITED;
0 rows inserted
可以看到,刪除錯誤記錄語句所不支持的列后,LOG ERRORS語句反而可以順利執行,而且無論DML語句是否包括哪些不支持列的數據。