How do I reset a sequence in Oracle?

后端 未结 18 1257
天命终不由人
天命终不由人 2020-11-22 05:09

In PostgreSQL, I can do something like this:

ALTER SEQUENCE serial RESTART WITH 0;

Is there an Oracle equivalent?

相关标签:
18条回答
  • 2020-11-22 05:36

    My approach is a teensy extension to Dougman's example.

    Extensions are...

    Pass in the seed value as a parameter. Why? I like to call the thing resetting the sequence back to the max ID used in some table. I end up calling this proc from another script which executes multiple calls for a whole bunch of sequences, resetting nextval back down to some level which is high enough to not cause primary key violations where I'm using the sequence's value for a unique identifier.

    It also honors the previous minvalue. It may in fact push the next value ever higher if the desired p_val or existing minvalue are higher than the current or calculated next value.

    Best of all, it can be called to reset to a specified value, and just wait until you see the wrapper "fix all my sequences" procedure at the end.

    create or replace
    procedure Reset_Sequence( p_seq_name in varchar2, p_val in number default 0)
    is
      l_current number := 0;
      l_difference number := 0;
      l_minvalue user_sequences.min_value%type := 0;
    
    begin
    
      select min_value
      into l_minvalue
      from user_sequences
      where sequence_name = p_seq_name;
    
      execute immediate
      'select ' || p_seq_name || '.nextval from dual' INTO l_current;
    
      if p_Val < l_minvalue then
        l_difference := l_minvalue - l_current;
      else
        l_difference := p_Val - l_current;
      end if;
    
      if l_difference = 0 then
        return;
      end if;
    
      execute immediate
        'alter sequence ' || p_seq_name || ' increment by ' || l_difference || 
           ' minvalue ' || l_minvalue;
    
      execute immediate
        'select ' || p_seq_name || '.nextval from dual' INTO l_difference;
    
      execute immediate
        'alter sequence ' || p_seq_name || ' increment by 1 minvalue ' || l_minvalue;
    end Reset_Sequence;
    

    That procedure is useful all by itself, but now let's add another one which calls it and specifies everything programmatically with a sequence naming convention and looking for the maximum value used in an existing table/field...

    create or replace
    procedure Reset_Sequence_to_Data(
      p_TableName varchar2,
      p_FieldName varchar2
    )
    is
      l_MaxUsed NUMBER;
    BEGIN
    
      execute immediate
        'select coalesce(max(' || p_FieldName || '),0) from '|| p_TableName into l_MaxUsed;
    
      Reset_Sequence( p_TableName || '_' || p_Fieldname || '_SEQ', l_MaxUsed );
    
    END Reset_Sequence_to_Data;
    

    Now we're cooking with gas!

    The procedure above will check for a field's max value in a table, builds a sequence name from the table/field pair and invokes "Reset_Sequence" with that sensed max value.

    The final piece in this puzzle and the icing on the cake comes next...

    create or replace
    procedure Reset_All_Sequences
    is
    BEGIN
    
      Reset_Sequence_to_Data( 'ACTIVITYLOG', 'LOGID' );
      Reset_Sequence_to_Data( 'JOBSTATE', 'JOBID' );
      Reset_Sequence_to_Data( 'BATCH', 'BATCHID' );
    
    END Reset_All_Sequences;
    

    In my actual database there are around one hundred other sequences being reset through this mechanism, so there are 97 more calls to Reset_Sequence_to_Data in that procedure above.

    Love it? Hate it? Indifferent?

    0 讨论(0)
  • 2020-11-22 05:37

    Here is a good procedure for resetting any sequence to 0 from Oracle guru Tom Kyte. Great discussion on the pros and cons in the links below too.

    tkyte@TKYTE901.US.ORACLE.COM> 
    create or replace
    procedure reset_seq( p_seq_name in varchar2 )
    is
        l_val number;
    begin
        execute immediate
        'select ' || p_seq_name || '.nextval from dual' INTO l_val;
    
        execute immediate
        'alter sequence ' || p_seq_name || ' increment by -' || l_val || 
                                                              ' minvalue 0';
    
        execute immediate
        'select ' || p_seq_name || '.nextval from dual' INTO l_val;
    
        execute immediate
        'alter sequence ' || p_seq_name || ' increment by 1 minvalue 0';
    end;
    /
    

    From this page: Dynamic SQL to reset sequence value
    Another good discussion is also here: How to reset sequences?

    0 讨论(0)
  • 2020-11-22 05:41

    Jezus, all this programming for just an index restart... Perhaps I'm an idiot, but for pre-oracle 12 (which has a restart feature), what is wrong with a simpel:

    drop sequence blah;
    create sequence blah 
    

    ?

    0 讨论(0)
  • 2020-11-22 05:42

    In my project, once it happened that someone manually entered the records without using sequence, hence I have to reset sequence value manually, for which I wrote below sql code snippet:

    declare
    max_db_value number(10,0);
    cur_seq_value number(10,0);
    counter number(10,0);
    difference number(10,0);
    dummy_number number(10);
    
    begin
    
    -- enter table name here
    select max(id) into max_db_value from persons;
    -- enter sequence name here
    select last_number into cur_seq_value from user_sequences where  sequence_name = 'SEQ_PERSONS';
    
    difference  := max_db_value - cur_seq_value;
    
     for counter in 1..difference
     loop
        -- change sequence name here as well
        select SEQ_PERSONS.nextval into dummy_number from dual;
     end loop;
    end;
    

    Please note, the above code will work if the sequence is lagging.

    0 讨论(0)
  • 2020-11-22 05:42

    You can use the CYCLE option, shown below:

    CREATE SEQUENCE test_seq
    MINVALUE 0
    MAXVALUE 100
    START WITH 0
    INCREMENT BY 1
    CYCLE;
    

    In this case, when the sequence reaches MAXVALUE (100), it will recycle to the MINVALUE (0).

    In the case of a decremented sequence, the sequence would recycle to the MAXVALUE.

    0 讨论(0)
  • 2020-11-22 05:43

    I create a block to reset all my sequences:

    DECLARE
        I_val number;
    BEGIN
        FOR US IN
            (SELECT US.SEQUENCE_NAME FROM USER_SEQUENCES US)
        LOOP
            execute immediate 'select ' || US.SEQUENCE_NAME || '.nextval from dual' INTO l_val;
            execute immediate 'alter sequence ' || US.SEQUENCE_NAME || ' increment by -' || l_val || ' minvalue 0';
            execute immediate 'select ' || US.SEQUENCE_NAME || '.nextval from dual' INTO l_val;
            execute immediate 'alter sequence ' || US.SEQUENCE_NAME || ' increment by 1 minvalue 0';
        END LOOP;
    END;
    
    0 讨论(0)
提交回复
热议问题