最近爲測試做一些數據導入,其中存在一些主子表,由於種種原因,子表有些記錄,外鍵值在主表無記錄,導致數據導入過程中,無法創建外鍵,
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可以使用腳本,也可以自行創建,但需要自行清理,利用這張表可以整理數據,糾正不規則數據。