Oracle違反約束數據的workaround

最近爲測試做一些數據導入,其中存在一些主子表,由於種種原因,子表有些記錄,外鍵值在主表無記錄,導致數據導入過程中,無法創建外鍵,

Failing sql is:

ALTER TABLE "A" ADD CONSTRAINT "FK_A_REF_B" FOREIGN KEY ("A_ID") REFERENCES "B" ("ID") ENABLE

ORA-39083: Object type REF_CONSTRAINT failed to create with error:

ORA-02298: cannot validate (FK_A_REF_B) - parent keys not found

 

此時若手工執行,

ALTER TABLE A ADD CONSTRAINT FK_A_REF_B FOREIGN KEY (A_ID) REFERENCES B (ID) ENABLE;

 

就會提示ORA-02298,

oerr ora 2298
02298, 00000,"cannot validate (%s.%s) - parent keys not found"
*Cause: an alter table validating constraint failed because the table has orphaned child records.
*Action: Obvious

 

這種數據不規則,難以滿足數據完整性要求。此時,可以使用not validate的方式,對歷史數據不進行約束控制,而只針對新數據開啓驗證。

alter table a add constraint fk_a_ref_b foreign key(a_id) references b(id) novalidate;

 

針對正在修改的數據,以及存在的數據,可以有不同的生效設置,Oracle官方文檔的介紹,

 

除此之外,還有個知識點,就是使用alter出現錯誤的數據,是可以自動捕獲,方便找出這些不規則數據,進一步手工操作。

 

首先需要創建一張exceptions表,有兩種創建方法,

1. Oracle提供了創建腳本。腳本路徑:$ORACLE_HOME/rdbms/admin/utlexpt1.sql,

Rem
Rem $Header: utlexpt1.sql 24-jun-99.07:59:18 echong Exp $
Rem
Rem utlexpt1.sql
Rem
Rem  Copyright (c) Oracle Corporation 1998, 1999. All Rights Reserved.
Rem
Rem    NAME
Rem      utlexpt1.sql - <one-line expansion of the name>
Rem
Rem    DESCRIPTION
Rem      <short description of component this file declares/defines>
Rem
Rem    NOTES
Rem      <other useful comments, qualifications, etc.>
Rem
Rem    MODIFIED   (MM/DD/YY)
Rem    echong      06/24/99 - rename
Rem    echong      06/05/98 - exceptions table with urowid type
Rem    echong      06/05/98 - Created
Rem

create table exceptions(row_id urowid,
                        owner varchar2(30),
                        table_name varchar2(30),
                        constraint varchar2(30));

 

 

執行腳本,

SQL> @$ORACLE_HOME/rdbms/admin/utlexpt1.sql
Table created.

SQL> desc exceptions;
 Name                                        Null?    Type
 ----------------------------------------- -------- ----------------------------
 ROW_ID                                               ROWID
 OWNER                                                VARCHAR2(30)
 TABLE_NAME                                      VARCHAR2(30)
 CONSTRAINT                                      VARCHAR2(30)

 

2. 可以不用腳本,自己創建這張表,表名可以任意。

create table exception_err(row_id urowid,
                        owner varchar2(30),
                        table_name varchar2(30),
                        constraint varchar2(30));

 

使用帶有exceptions into子句的alter table,

alter table A enable validate constraint FK_A_REF_B exceptions into exceptions;

 

此時提示ORA-02298錯誤,但是exceptions表已經存在數據了,

 

下面可以根據rowid,定位A表違規數據,要麼刪除,要麼改造,讓其符合約束,進而就可以正常執行。

select * from A where rowid in (select row_id from exceptions);

 

需要注意的是,exceptions是一張普通堆表,因此存儲的數據,需要自行清理,要麼執行truncate,要麼執行drop。

 

總結:

1. 針對不規則數據,可以使用alter table ... NOVALIDATE,對歷史數據不做約束,只約束新增數據。

2. alter table可以使用exceptions into子句,讓非法數據自動記錄,異常表exceptions可以使用腳本,也可以自行創建,但需要自行清理,利用這張表可以整理數據,糾正不規則數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章