Home » SQL & PL/SQL » SQL & PL/SQL » Identity column inserts duplicates with Insert All statement, unique constraint violation (Oracle database, 12.1.0.2, Any OS)
Identity column inserts duplicates with Insert All statement, unique constraint violation [message #633352] Tue, 17 February 2015 00:06 Go to next message
Lalit Kumar B
Messages: 3174
Registered: May 2013
Location: World Wide on the Web
Senior Member
This seems to be a big problem with Identity columns. The sequence of the Identity column doesn't progress to nextval when an Insert All statement is executed. Thus, inserting duplicate keys which raises ORA-00001: unique constraint violation error. Yes, it seems a obvious thing, as the same would happen if we use an explicit sequence instead of identity column. However, it was never an issue with the old trigger-sequence approach. Since, we create a row level trigger.

Set up -

DROP TABLE t PURGE;

CREATE TABLE t (
  ID NUMBER GENERATED ALWAYS AS IDENTITY,
  text VARCHAR2(50),
  CONSTRAINT id_pk PRIMARY KEY (ID)
);


Test -

SQL> CREATE TABLE t (
  2    ID NUMBER GENERATED ALWAYS AS IDENTITY,
  3    text VARCHAR2(50),
  4    CONSTRAINT id_pk PRIMARY KEY (ID)
  5  );

Table created.

SQL>
SQL> INSERT ALL
  2    INTO t (text) VALUES ('a')
  3    INTO t (text) VALUES ('b')
  4    INTO t (text) VALUES ('c')
  5    INTO t (text) VALUES ('d')
  6  SELECT * FROM dual;
INSERT ALL
*
ERROR at line 1:
ORA-00001: unique constraint (LALIT.ID_PK) violated


SQL>


Though it works with a INSERT-INTO-SELECT -

SQL> INSERT INTO t(text) SELECT 'Level '||LEVEL FROM dual CONNECT BY LEVEL <= 4;

4 rows created.

SQL>
SQL> SELECT * FROM t;

        ID TEXT
---------- --------------------------------------------------
         2 Level 1
         3 Level 2
         4 Level 3
         5 Level 4

SQL>


Disabling the constraint and subsequent insert reveals the issue -

SQL> ALTER TABLE t
  2    DISABLE CONSTRAINT id_pk;

Table altered.

SQL>
SQL> INSERT ALL
  2    INTO t (text) VALUES ('a')
  3    INTO t (text) VALUES ('b')
  4    INTO t (text) VALUES ('c')
  5    INTO t (text) VALUES ('d')
  6  SELECT * FROM dual;

4 rows created.

SQL>
SQL> SELECT * FROM t;

        ID TEXT
---------- ----------------------
         2 Level 1
         3 Level 2
         4 Level 3
         5 Level 4
         6 a
         6 b
         6 c
         6 d

8 rows selected.

SQL>


Well, the same would happen even if we don't use an Identity column, and use a sequence explicitly.

SQL> DROP SEQUENCE s;

Sequence dropped.

SQL>
SQL> CREATE SEQUENCE s;

Sequence created.

SQL>
SQL> DROP TABLE t PURGE;

Table dropped.

SQL>
SQL> CREATE TABLE t (
  2    ID NUMBER,
  3    text VARCHAR2(50),
  4    CONSTRAINT id_pk PRIMARY KEY (ID)
  5  );

Table created.

SQL>
SQL> INSERT ALL
  2    INTO t VALUES (s.nextval, 'a')
  3    INTO t VALUES (s.nextval, 'b')
  4    INTO t VALUES (s.nextval, 'c')
  5    INTO t VALUES (s.nextval, 'd')
  6  SELECT * FROM dual;
INSERT ALL
*
ERROR at line 1:
ORA-00001: unique constraint (LALIT.ID_PK) violated


SQL>
SQL> SELECT * FROM T;

no rows selected

SQL>
SQL> ALTER TABLE t
  2    DISABLE CONSTRAINT id_pk;

Table altered.

SQL> INSERT ALL
  2    INTO t VALUES (s.nextval, 'a')
  3    INTO t VALUES (s.nextval, 'b')
  4    INTO t VALUES (s.nextval, 'c')
  5    INTO t VALUES (s.nextval, 'd')
  6  SELECT * FROM dual;

4 rows created.

SQL> SELECT * FROM T;

        ID TEXT
---------- ----------------------------------------
         2 a
         2 b
         2 c
         2 d

SQL>


The only possible workaround that come to my mind is, the old method of using a ROW level trigger.

SQL> CREATE OR REPLACE TRIGGER t_trg
  2      BEFORE INSERT ON t
  3      FOR EACH ROW
  4      WHEN (new.id IS NULL)
  5      BEGIN
  6        SELECT s.NEXTVAL
  7        INTO   :new.id
  8        FROM   dual;
  9      END;
 10  /

Trigger created.

SQL> truncate table t;

Table truncated.

SQL> INSERT ALL
  2    INTO t (text) VALUES ('a')
  3    INTO t (text) VALUES ('b')
  4    INTO t (text) VALUES ('c')
  5    INTO t (text) VALUES ('d')
  6  SELECT * FROM dual;

4 rows created.

SQL> SELECT * FROM t;

        ID TEXT
---------- -------------------------
         3 a
         4 b
         5 c
         6 d

SQL>



Regards,
Lalit
Re: Identity column inserts duplicates with Insert All statement, unique constraint violation [message #633354 is a reply to message #633352] Tue, 17 February 2015 00:15 Go to previous messageGo to next message
Littlefoot
Messages: 21826
Registered: June 2005
Location: Croatia, Europe
Senior Member
Account Moderator
Lalit

the same would happen even if we don't use an Identity column, and use a sequence explicitly.

Here's what I think: as IDENTITY column's background actually is a good, old sequence (and you can't use sequences that way anyway, you never could - as far as I can tell), no wonder that identity column's behavior is just the same as sequence's. So I wouldn't call it a bug or a big problem, it's just the way it works.
Re: Identity column inserts duplicates with Insert All statement, unique constraint violation [message #633359 is a reply to message #633352] Tue, 17 February 2015 01:41 Go to previous messageGo to next message
John Watson
Messages: 9003
Registered: January 2010
Location: Global Village
Senior Member
This is documented behaviour. From here, http://docs.oracle.com/database/121/SQLRF/pseudocolumns002.htm#SQLRF50946
Quote:
For each INSERT ... [ALL | FIRST] statement (multitable insert). A multitable insert is considered a single SQL statement. Therefore, a reference to the NEXTVAL of a sequence will increase the sequence only once for each input record coming from the SELECT portion of the statement. If NEXTVAL is specified more than once in any part of the INSERT ... [ALL | FIRST ] statement, then the value will be the same for all insert branches, regardless of how often a given record might be inserted.
Similar to my recent question regarding a non-deterministic update, the result is reasonable.

[Updated on: Tue, 17 February 2015 01:42]

Report message to a moderator

Re: Identity column inserts duplicates with Insert All statement, unique constraint violation [message #633360 is a reply to message #633354] Tue, 17 February 2015 01:46 Go to previous messageGo to next message
Michel Cadot
Messages: 68776
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

And the way it is designed and documented.

Quote:
Within a single SQL statement containing a reference to NEXTVAL, Oracle increments the sequence once:


[Updated on: Tue, 17 February 2015 01:47]

Report message to a moderator

Re: Identity column inserts duplicates with Insert All statement, unique constraint violation [message #633365 is a reply to message #633360] Tue, 17 February 2015 02:20 Go to previous message
Lalit Kumar B
Messages: 3174
Registered: May 2013
Location: World Wide on the Web
Senior Member
I agree with you all, the behavior of the sequence is the way it is designed and documented. It would increment once for an INSERT ALL. My point is, I never cared about this previously using the trigger based approach. It just happened that I was working on Identity columns and all my scripts failed with the unique constraint violation error. Actually I took the Insert All statements from another developer, merged both scripts, my DDL with his DML statements. Now, his DML script is of no use to me Sad I had to split each INSERT ALL statement into individual inserts.

Thanks LF, John and Michel.
Previous Topic: "Client copy" with PL/SQL
Next Topic: Concatenating numbers in virtual column expression throws ORA-12899: value too large for column
Goto Forum:
  


Current Time: Thu Aug 27 02:15:10 CDT 2026