PLSQL: Anonymous block to reset out-of-sync (too low) sequence

I wrote a short little PLSQL to fix an out-of-sync sequence issue. For some unknown reasons, there was stored primary key values in the database which was way larger than the currval for the dedicated sequence.

Test case:

SQL> drop table big_table;

Table BIG_TABLE dropped.

SQL> drop sequence big_table_seq;

Sequence BIG_TABLE_SEQ dropped.

SQL> create table big_table as select * from all_objects where rownum<=10;

Table BIG_TABLE created.

SQL> update big_table set object_id=rownum;

10 rows updated.

SQL> alter table big_table add constraint big_table_pk primary key (object_id);

Table BIG_TABLE altered.

SQL> create sequence big_table_seq start with 1 increment by 1 cache 100;

Sequence BIG_TABLE_SEQ created.

SQL> INSERT INTO big_table (OWNER,OBJECT_NAME,SUBOBJECT_NAME,OBJECT_ID,
  2                         DATA_OBJECT_ID,OBJECT_TYPE,CREATED,LAST_DDL_TIME,
  3                         TIMESTAMP,STATUS,TEMPORARY,GENERATED,SECONDARY,
  4                         NAMESPACE,EDITION_NAME,SHARING,EDITIONABLE,ORACLE_MAINTAINED) 
  5     VALUES ('LASSE','LASSE',null,big_table_seq.nextval,
  6             null,'TEST',to_date('07.07.2014','DD.MM.RRRR'),to_date('07.07.2014','DD.MM.RRRR'),
  7             '2014-07-07:05:39:03','TEST','N','N','N',
  8             '64','NONE',null,'Y','N');

Error starting at line : 11 in command -
INSERT INTO big_table (OWNER,OBJECT_NAME,SUBOBJECT_NAME,OBJECT_ID,
                       DATA_OBJECT_ID,OBJECT_TYPE,CREATED,LAST_DDL_TIME,
                       TIMESTAMP,STATUS,TEMPORARY,GENERATED,SECONDARY,
                       NAMESPACE,EDITION_NAME,SHARING,EDITIONABLE,ORACLE_MAINTAINED) 
   VALUES ('LASSE','LASSE',null,big_table_seq.nextval,
           null,'TEST',to_date('07.07.2014','DD.MM.RRRR'),to_date('07.07.2014','DD.MM.RRRR'),
           '2014-07-07:05:39:03','TEST','N','N','N',
           '64','NONE',null,'Y','N')
Error report -
ORA-00001: brudd på unik skranke (LJ.BIG_TABLE_PK)

As we see the sequence is out-of-sync, as there is already stored values higher than the sequence nextval.
The following PL/SQL anonymous block fixed the issue:

set serveroutput on size 1000000
DECLARE
-------------------------------------------------
-- Description
-- Anonymous PLSQL Block to correct sequence
-------------------------------------------------

--------------------------------
-- WARNING! Set variables below
--------------------------------
   l_seq_name        VARCHAR2(30)   := 'BIG_TABLE_SEQ';
   l_tbl_name        VARCHAR2(30)   := 'BIG_TABLE';
   l_tbl_pk_col      VARCHAR2(30)   := 'OBJECT_ID';

   l_seq_current     NUMBER;
   l_seq_max         NUMBER;
   l_dummy           NUMBER;
   
   l_sql             VARCHAR2(4000);
   
   procedure run_sql(sql_i varchar2) as
   begin
      l_sql := sql_i;
      EXECUTE IMMEDIATE l_sql;
      dbms_output.put_line('SQL: ' || sql_i);
   end;
   procedure run_sql(sql_i varchar2, value_o OUT number) as
   begin
      l_sql := sql_i;
      EXECUTE IMMEDIATE l_sql INTO value_o;
      dbms_output.put_line('SQL: ' || sql_i);
   end;
BEGIN
   -- Get maxvalue
   run_sql('SELECT max(' || l_tbl_pk_col || ') FROM ' || l_tbl_name, l_seq_max);
   
   -- Get sequence currval
   run_sql('SELECT ' || l_seq_name || '.nextval FROM dual',l_seq_current);
   
   -- Adjust sequence
   run_sql('ALTER SEQUENCE ' || l_seq_name || ' INCREMENT BY ' || (l_seq_max - l_seq_current));
   run_sql('SELECT ' || l_seq_name || '.nextval FROM dual', l_dummy);
   run_sql('ALTER SEQUENCE ' || l_seq_name || ' INCREMENT BY 1');
EXCEPTION WHEN OTHERS THEN
   dbms_output.put_line('ERROR: ' || l_sql);
END;
/

The output when running the PLSQL block:

SQL: SELECT max(OBJECT_ID) FROM BIG_TABLE
SQL: SELECT BIG_TABLE_SEQ.nextval FROM dual
SQL: ALTER SEQUENCE BIG_TABLE_SEQ INCREMENT BY 8
SQL: SELECT BIG_TABLE_SEQ.nextval FROM dual
SQL: ALTER SEQUENCE BIG_TABLE_SEQ INCREMENT BY 1

PL/SQL procedure successfully completed.

Now we can run the insert again:

SQL> INSERT INTO big_table (OWNER,OBJECT_NAME,SUBOBJECT_NAME,OBJECT_ID,
  2                         DATA_OBJECT_ID,OBJECT_TYPE,CREATED,LAST_DDL_TIME,
  3                         TIMESTAMP,STATUS,TEMPORARY,GENERATED,SECONDARY,
  4                         NAMESPACE,EDITION_NAME,SHARING,EDITIONABLE,ORACLE_MAINTAINED) 
  5     VALUES ('LASSE','LASSE',null,big_table_seq.nextval,
  6             null,'TEST',to_date('07.07.2014','DD.MM.RRRR'),to_date('07.07.2014','DD.MM.RRRR'),
  7             '2014-07-07:05:39:03','TEST','N','N','N',
  8             '64','NONE',null,'Y','N');

1 row inserted.

Post a Comment

Your email is never published nor shared. Required fields are marked *