Since version 11.1, Data Pump Import supports the SKIP_CONSTRAINT_ERRORS option, which specifies that you want the import operation to proceed even if (non-deferred) constraint violations are encountered. It logs any rows that cause constraint violations, but does not stop, and does load the other rows. If SKIP_CONSTRAINT_ERRORS is not set, then the default behavior is to roll back the entire load of the data object on which constraint violations are encountered.
For example:
The table presidents was created by the following statement:
create table presidents (
id number primary key,
first_name varchar2(20),
last_name varchar2(20)
);
and is currently containing the following data:
ID FIRST_NAME LAST_NAME
---------- -------------------- --------------------
1 George Washington
2 John Adams
3 Thomas Jefferson
4 James Madison
5 James Monroe
6 John Quincy Adams
7 Andrew Jackson
8 Martin Van Buren
We have a dump file that contains an export of the presidents table (from somewhere else or from some previous point in time), and we’d like to append the data from the dump file to the table.
The dump file contains the following data:
ID FIRST_NAME LAST_NAME
---------- -------------------- --------------------
7 William Harrison
8 John Tyler
9 James Polk
10 Zachary Taylor
11 Millard Fillmore
12 Franklin Pierce
Obviously, the records with ID 7 and 8 cannot be added to the table, because a primary key constraint is defined on the ID column, and the table already contains records with these ID values.
If we try to execute the following import, without the SKIP_CONSTRAINT_ERRORS option, we will get an error and the whole operation will be rolled back:
impdp oren/oren tables=presidents dumpfile=presidents.dmp table_exists_action=append logfile=presidents_imp1.log
Import: Release 11.2.0.4.0 - Production on Fri Jul 18 19:33:33 2014
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
Connected to: Oracle Database 11g Release 11.2.0.1.0 - 64bit Production
Master table "OREN"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded
Starting "OREN"."SYS_IMPORT_TABLE_01": oren/******** tables=presidents dumpfile=presidents.dmp table_exists_action=append logfile=presidents_imp1.log
Processing object type TABLE_EXPORT/TABLE/TABLE
ORA-39152: Table "OREN"."PRESIDENTS" exists. Data will be appended to existing table but all dependent metadata will be skipped due to table_exists_action of append
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
ORA-31693: Table data object "OREN"."PRESIDENTS" failed to load/unload and is being skipped due to error:
ORA-00001: unique constraint (OREN.SYS_C0023857) violated
Processing object type TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Job "OREN"."SYS_IMPORT_TABLE_01" completed with 2 error(s) at 16:33:35
As expected, if we check the contents of the table we see that no records have been added from the dump file:
select * from presidents;
ID FIRST_NAME LAST_NAME
---------- -------------------- --------------------
1 George Washington
2 John Adams
3 Thomas Jefferson
4 James Madison
5 James Monroe
6 John Quincy Adams
7 Andrew Jackson
8 Martin Van Buren
Now let’s execute the import with the SKIP_CONSTRAINT_ERRORS option:
impdp oren/oren tables=presidents dumpfile=presidents.dmp table_exists_action=append logfile=presidents_imp2.log data_options=SKIP_CONSTRAINT_ERRORS
Import: Release 11.2.0.4.0 - Production on Fri Jul 18 19:38:00 2014
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
Connected to: Oracle Database 11g Release 11.2.0.1.0 - 64bit Production
Master table "OREN"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded
Starting "OREN"."SYS_IMPORT_TABLE_01": oren/******** tables=presidents dumpfile=presidents.dmp table_exists_action=append logfile=presidents_imp2.log data_options=SKIP_CONSTRAINT_ERRORS
Processing object type TABLE_EXPORT/TABLE/TABLE
ORA-39152: Table "OREN"."PRESIDENTS" exists. Data will be appended to existing table but all dependent metadata will be skipped due to table_exists_action of append
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
. . imported "OREN"."PRESIDENTS" 5.945 KB 4 out of 6 rows
2 row(s) were rejected with the following error:
ORA-00001: unique constraint (OREN.SYS_C0023857) violated
Rejected rows with the primary keys are:
Rejected row #1:
column ID: 7
Rejected row #2:
column ID: 8
Processing object type TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Job "OREN"."SYS_IMPORT_TABLE_01" completed with 1 error(s) at 16:38:06
We see that 4 rows were imported and that 2 rows were rejected due to unique constraint violation. We can also see from the log which rows were rejected, or more precisely, what are the primary key values of the rejected rows.
But what if we want to know the values of the other columns in the rejected rows?
I don’t know about such a feature, but I made some “digging” and succeeded to come out with a solution.
First I looked at the statements that Data Pump did behind the scenes (by querying V$SQL), and one of the statements I found was this:
INSERT INTO "OREN"."ERR$DP004BC9640001" (
ORA_ERR_NUMBER$, ORA_ERR_MESG$, ORA_ERR_ROWID$, ORA_ERR_OPTYP$, ORA_ERR_TAG$,
"ID", "FIRST_NAME", "LAST_NAME")
VALUES (:1, :2, :3, :4, :5, :6, :7, :8)
So apparently Data Pump simply uses DML Error Logging to support the SKIP_CONSTRAINT_ERRORS option. And this means that the values of all the columns (except for LOBs etc.) of the rejected rows are basically available. All we need to do is to select from this ERR$DP004BC9640001 table, right?
Well, there are two problems with this:
- The name of the table is not consistent. I ran it several times and got a different name in each run (but it always started with ERR$DP).
- The ERR$DP… table is dropped as soon as the import is done, so by the time we want to select from it, it is already gone.
But we can overcome these issues, with the following flow:
1. Before starting the import process, open a SQL*Plus session and execute:
lock table presidents in share mode;
and keep this session (and transaction) open. This will block the import process (as well as any other process!) when it tries to insert records into the table, and will give us the opportunity to check the name of the error logging table, which, as we’ll see, will already exist at that point in time.
2. Start the import:
impdp oren/oren tables=presidents dumpfile=presidents.dmp table_exists_action=append logfile=presidents_imp.log data_options=SKIP_CONSTRAINT_ERRORS
Import: Release 11.2.0.4.0 - Production on Fri Jul 18 23:13:14 2014
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
Connected to: Oracle Database 11g Release 11.2.0.1.0 - 64bit Production
Master table "OREN"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded
Starting "OREN"."SYS_IMPORT_TABLE_01": oren/******** tables=presidents dumpfile=presidents.dmp table_exists_action=append logfile=presidents_imp.log data_options=SKIP_CONSTRAINT_ERRORS
Processing object type TABLE_EXPORT/TABLE/TABLE
ORA-39152: Table "OREN"."PRESIDENTS" exists. Data will be appended to existing table but all dependent metadata will be skipped due to table_exists_action of append
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
3. The import is blocked now. Going back to the SQL*Plus session, let’s find out the error logging table name:
select table_name from user_tables where table_name like 'ERR$DP%';
TABLE_NAME
-----------------------
ERR$DP0047ABBF0001
4. Start a second SQL*Plus session and lock the error logging table in a mode that will allow the import to fill it but not to drop it:
lock table ERR$DP0047ABBF0001 in row share mode;
5. In the first SQL*Plus session, release the lock on the presidents table so the import can continue:
Rollback;
And the import continues:
. . imported "OREN"."PRESIDENTS" 5.945 KB 4 out of 6 rows
2 row(s) were rejected with the following error:
ORA-00001: unique constraint (OREN.SYS_C0023889) violated
Rejected rows with the primary keys are:
Rejected row #1:
column ID: 7
Rejected row #2:
column ID: 8
Processing object type TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Job "OREN"."SYS_IMPORT_TABLE_01" completed with 1 error(s) at 20:35:21
6. When the import is done, we can see all the rejected rows from one of the SQL*Plus sessions:
select id,first_name,last_name from ERR$DP0047ABBF0001;
ID FIRST_NAME LAST_NAME
--- -------------------- --------------------
7 William Harrison
8 John Tyler
7. And finally, to cleanup, we can drop the error logging table from the second SQL*Plus session:
drop table ERR$DP0047ABBF0001;
You are most welcome to comment or to ask questions in this page, or to write me at oren@db-oriented.com.