Search code examples
oracleinsertduplicatesunique-constraint

Oracle 'INSERT ALL' ignore duplicates


I have a database table with a unique constraint on it (unique (DADSNBR, DAROLEID) pair). I am going to be inserting multiple values into this table simultaneously, so I'd like to get it done using one query - I'm assuming this would be the faster way. My query is thus:

INSERT ALL
    INTO ACCESS (DADSNBR, DAROLEID) VALUES (68, 1)
    INTO ACCESS (DADSNBR, DAROLEID) VALUES (68, 2)
    INTO ACCESS (DADSNBR, DAROLEID) VALUES (68, 3)
    INTO ACCESS (DADSNBR, DAROLEID) VALUES (68, 4)
SELECT 1 FROM DUAL

Since there are some entries within the statement that are duplicates of those already in the database, the whole insert fails and none of the rows are inserted.

Is there a way to ignore the cases where the unique constraint fails, and just insert the ones that are unique, without having to split it up into individual INSERT statements?

Edit: I realised I probably don't want to do this anyway, but I'm still curious as to whether it's possible or not.


Solution

  • In Oracle, statements either succeed completely or fail completely (they are atomic). However, you can add clauses in certain cases to log exceptions instead of raising errors:

    The second method is all automatic, here's a demo (using 11gR2):

    SQL> CREATE TABLE test (pk1 NUMBER,
      2                     pk2 NUMBER,
      3                     CONSTRAINT pk_test PRIMARY KEY (pk1, pk2));
    
    Table created.
    
    SQL> /* Statement fails because of duplicate */
    SQL> INSERT into test (SELECT 1, 1 FROM dual CONNECT BY LEVEL <= 2);
    
    ERROR at line 1:
    ORA-00001: unique constraint (VNZ.PK_TEST) violated
    
    SQL> BEGIN dbms_errlog.create_error_log('TEST'); END;
      2  /
    
    PL/SQL procedure successfully completed.
    
    SQL> /* Statement succeeds and the error will be logged */
    SQL> INSERT into test (SELECT 1, 1 FROM dual CONNECT BY LEVEL <= 2)
      2   LOG ERRORS REJECT LIMIT UNLIMITED;
    
    1 row(s) inserted.
    
    SQL> select ORA_ERR_MESG$, pk1, pk2 from err$_test;
    
    ORA_ERR_MESG$                                       PK1 PK2
    --------------------------------------------------- --- ---
    ORA-00001: unique constraint (VNZ.PK_TEST) violated   1   1
    

    You can use the LOG ERROR clause with INSERT ALL (thanks @Alex Poole), but you have to add the clause after each table:

    SQL> INSERT ALL
      2   INTO test VALUES (1, 1) LOG ERRORS REJECT LIMIT UNLIMITED
      3   INTO test VALUES (1, 1) LOG ERRORS REJECT LIMIT UNLIMITED
      4  (SELECT * FROM dual);
    
    0 row(s) inserted.