Sequences
June 8, 2002 - 7pm Central time zone
Reviewer: Monz from Reston, USA
Tom:
1. How would dropping the sequence invalidate objects. I have several procedures that do inserts
and use sequences and was thinking of dropping and recreating sometimes. Would I get an error? I
think I tried it before without a problem? I guess you would if you run the procedure and the
sequence was not there?
2. Let us say I want to reset a sequence dynamically based on the maximum number in a column. If
the max number is 20, I want start with 21.
Can I use a variable to do the increment like:
select max(col) into v_seq from table;
column S new_val inc;
select seq.nextval S from dual;
alter sequence seq increment by -&inc minvalue 0;
alter sequence seq increment by v_seq;
alter sequence seq increment by 1;
3. Problem is that on one web form I use a seqeunce to show user a unique order number that he
wants to see before saving record. If user cancels then I have a gap in my orders saved. Is there
a way around it?
Followup June 9, 2002 - 10am Central time zone:
1) You have a procedure.
This procedure does an insert.
This insert references a sequence.
Hence, the procedure is dependent on the sequence. If you drop the sequence -- the procedure will
go invalid since an object it depends on no longer exists. If you run the procedure right now,
it'll fail to compile. If you create the sequence and then run the procedure, it'll successfully
recompile itself automagically.
So, if you drop and recreate, it'll just invalidate which is a waste of your computer resources but
will not result in an error.
2) No, no it won't. You never select from it after the alters, hence the numbers will never
change.
You could of course do this in two alters as follows (simple math going on here):
ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t (x int);
Table created.
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( dbms_random.value(1,99999999) );
1 row created.
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t;
X
----------
68637521
ops$tkyte@ORA817DEV.US.ORACLE.COM> column inc new_val INC;
ops$tkyte@ORA817DEV.US.ORACLE.COM> select max_x-s.nextval+1 inc
2 from ( select max(x) max_x from t );
INC
----------
68637399
ops$tkyte@ORA817DEV.US.ORACLE.COM> alter sequence s increment by &inc;
old 1: alter sequence s increment by &inc
new 1: alter sequence s increment by 68637399
Sequence altered.
ops$tkyte@ORA817DEV.US.ORACLE.COM> select s.nextval from dual;
NEXTVAL
----------
68637522
ops$tkyte@ORA817DEV.US.ORACLE.COM> alter sequence s increment by 1;
Sequence altered.
ops$tkyte@ORA817DEV.US.ORACLE.COM> select s.nextval from dual;
NEXTVAL
----------
68637523
ops$tkyte@ORA817DEV.US.ORACLE.COM> update t set x = 2;
1 row updated.
ops$tkyte@ORA817DEV.US.ORACLE.COM> select max_x-s.nextval+1 inc
2 from ( select max(x) max_x from t );
INC
----------
-68637521
ops$tkyte@ORA817DEV.US.ORACLE.COM> alter sequence s increment by &inc;
old 1: alter sequence s increment by &inc
new 1: alter sequence s increment by -68637521
Sequence altered.
ops$tkyte@ORA817DEV.US.ORACLE.COM> select s.nextval from dual;
NEXTVAL
----------
3
ops$tkyte@ORA817DEV.US.ORACLE.COM> alter sequence s increment by 1;
Sequence altered.
ops$tkyte@ORA817DEV.US.ORACLE.COM> select s.nextval from dual;
NEXTVAL
----------
4
3) the way around this is TO NOT WORRY ABOUT GAPS AS GAPS ARE INEVITABLE IN A SEQUENCE.
There are three things I am sure of in life:
o Death
o Taxes
o Gaps in my sequences
Neat idea
June 9, 2002 - 2pm Central time zone
Reviewer: Doug from Danbury, CT USA
I always drop and recreate. This is an interesting idea to just increment backwards.
6 months early!
June 10, 2002 - 9am Central time zone
Reviewer: Santa's helper from like a rat in a cage I am trapped inside the cubicle
Didn't Christmas used to come in December and not June? :-)
follow up
June 28, 2002 - 7pm Central time zone
Reviewer: ramesh Konda from Minnesota
I tried the following and ran into errors. Please advise.
1* alter sequence s_cust_mgmt_group_cmg_id increment by -&inc minvalue
SQL> /
Enter value for inc: 0
old 1: alter sequence s_cust_mgmt_group_cmg_id increment by -&inc minvalue
new 1: alter sequence s_cust_mgmt_group_cmg_id increment by -0 minvalue
alter sequence s_cust_mgmt_group_cmg_id increment by -0 minvalue
*
ERROR at line 1:
ORA-01722: invalid number
SQL> alter sequence s_cust_mgmt_group_cmg_id increment by -&inc minvalue 0
2 /
Enter value for inc: 0
old 1: alter sequence s_cust_mgmt_group_cmg_id increment by -&inc minvalue 0
new 1: alter sequence s_cust_mgmt_group_cmg_id increment by -0 minvalue 0
alter sequence s_cust_mgmt_group_cmg_id increment by -0 minvalue 0
*
ERROR at line 1:
ORA-04002: INCREMENT must be a non-zero integer
SQL> ed
Wrote file afiedt.buf
1* alter sequence s_cust_mgmt_group_cmg_id increment by -&inc minvalue 1
SQL> /
Enter value for inc: 1
old 1: alter sequence s_cust_mgmt_group_cmg_id increment by -&inc minvalue 1
new 1: alter sequence s_cust_mgmt_group_cmg_id increment by -1 minvalue 1
Sequence altered.
SQL> select s_cust_mgmt_group_cmg_id.nextval from dual;
NEXTVAL
----------
23
****** It did not set the sequence to initial value ******
Followup June 28, 2002 - 7pm Central time zone:
you missed a zero
old 1: alter sequence s_cust_mgmt_group_cmg_id increment by -&inc minvalue
new 1: alter sequence s_cust_mgmt_group_cmg_id increment by -0 minvalue
alter sequence s_cust_mgmt_group_cmg_id increment by -0 minvalue
*
ERROR at line 1:
ORA-01722: invalid number
after MINVALUE.
and then you tried to set the increment to 0, which just isn't allowed (as evidenced by the
ora-4002 error)
You need to read the example above again (slower). We get the next val, change the increment to be
that (negative), select once to get it to zero and then reset the increment to +1. You didn't do
any of that.
Just use the code I provided:
column S new_val inc;
select seq.nextval S from dual;
alter sequence seq increment by -&inc minvalue 0;
select seq.nextval S from dual;
alter sequence seq increment by 1;
select seq.nextval from dual;
do that, as is, and it'll work as advertised.
How to change START WITH for a sequence
February 2, 2003 - 8pm Central time zone
Reviewer: Ajeet from cincinnati
Tom- based on the above disucssion --can we change the start with value of sequence too.
?
Followup February 3, 2003 - 7am Central time zone:
just reset the value to be whatever "start with" value you want.
say the sequence was created:
create sequence s;
and you are currently at 1,000 and want the sequence to now "start with 50", just use -950 instead
of -1000 when you change the increment by to "reset" it.

June 25, 2003 - 10am Central time zone
Reviewer: A reader

February 7, 2004 - 3am Central time zone
Reviewer: Prince from Pakistan
Hi Tom!
I have two databases prod and test. test dababase has been populated by importing one month old
dump of prod. Now here is a requirement. we want to see the next values of sequences of test
database at least equal to prod database's sequence next values. Can you guide plz... how can it be
done?
Thanks as always :)
Followup February 7, 2004 - 3pm Central time zone:
you'd have to goto prod, grab the sequence name and last_number from dba_sequences.
Then you can use the technique above in test to reset to zero, change the increment to last_number
and select nextval (hence making the sequence "be at" last_number, then change the increment to 1
again and it'll be done.
something like this (on test -- table t would be created as select from user_sequences on the other
machine and moved over)
ops$tkyte@ORA9IR2> create table t ( s_name varchar2(30), last_number number );
Table created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> create sequence s1 increment by 212321;
Sequence created.
ops$tkyte@ORA9IR2> create sequence s2 increment by 2352;
Sequence created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select s1.nextval, s2.nextval from dual;
NEXTVAL NEXTVAL
---------- ----------
1 1
ops$tkyte@ORA9IR2> select s1.nextval, s2.nextval from dual;
NEXTVAL NEXTVAL
---------- ----------
212322 2353
ops$tkyte@ORA9IR2> alter sequence s1 increment by 1;
Sequence altered.
ops$tkyte@ORA9IR2> alter sequence s2 increment by 1;
Sequence altered.
ops$tkyte@ORA9IR2> select s1.nextval, s2.nextval from dual;
NEXTVAL NEXTVAL
---------- ----------
212323 2354
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> insert into t values ( 'S1', 523323 );
1 row created.
ops$tkyte@ORA9IR2> insert into t values ( 'S2', 10023 );
1 row created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> create or replace procedure reset_sequences
2 as
3 l_dummy number;
4 begin
5 for x in ( select * from t )
6 loop
7 execute immediate 'select ' || x.s_name || '.nextval from dual' into l_dummy;
8
9 execute immediate 'alter sequence ' || x.s_name ||
10 ' increment by -' || (l_dummy-1);
11
12 execute immediate 'select ' || x.s_name || '.nextval from dual' into l_dummy;
13
14 execute immediate 'alter sequence ' || x.s_name ||
15 ' increment by ' || x.last_number;
16
17 execute immediate 'select ' || x.s_name || '.nextval from dual' into l_dummy;
18
19 dbms_output.put_line( 'last selected value from ' || x.s_name || ' was ' ||
l_dummy );
20 end loop;
21 end;
22 /
Procedure created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> exec reset_sequences;
last selected value from S1 was 523324
last selected value from S2 was 10024
PL/SQL procedure successfully completed.
Set the sequece present value to a particular number.
May 13, 2004 - 12pm Central time zone
Reviewer: Sujit Mondal from NY , USA
Hi Tom,
Can you please let me know if there is any way , we can set the vaule of a sequence to a
particular number.
eg.
select S783_INT_NBC_PGM_CD_DM_ID.nextval FROM DUAL
gives me the result 100275
I want to set the value of S783_INT_NBC_PGM_CD_DM_ID to 101907 so that when I refer the
S783_INT_NBC_PGM_CD_DM_ID.nextval
later on I will get 101908.
-Sujit
Followup May 13, 2004 - 3pm Central time zone:
hmmm, just like in the fashion I set it to zero above?
sure, just change the increment to be the difference between the NEXTVAL and your desired value
select DESIRED_VALE - s.nextval my_new_increment from dual;
alter the sequence to increment by that.
select s.nextval from dual;
alter the sequence to increment by 1
Gaps
May 28, 2004 - 8am Central time zone
Reviewer: Jason from Ontario, Canada
To avoid gaps, can't you just use currval everytime and only increment the sequence with nextval if
and only if it is actually used?
Followup May 28, 2004 - 11am Central time zone:
no.
gaps happen due to cache.
gaps happen due to rollback.
gaps are pretty much unavoidable with sequences and everything else serializes (one transaction at
a time)
very good
November 24, 2004 - 12am Central time zone
Reviewer: shyam from india
this has given very clear understanding of how to rollback a sequnce value to pevious value
reset all sequences
May 17, 2005 - 11am Central time zone
Reviewer: A reader
hi
how to reset all sequences in the database in one go.
Thanks
Followup May 17, 2005 - 2pm Central time zone:
there isn't any way.
user's env
May 17, 2005 - 2pm Central time zone
Reviewer: A reader
In a schema ?
Followup May 17, 2005 - 2pm Central time zone:
one at a time.
Tom's code from another post
May 17, 2005 - 2pm Central time zone
Reviewer: Jeff from Atlanta
ops$tkyte@ORA920LAP> create or replace procedure set_seq_to( p_name in varchar2,
p_val in number )
2 as
3 l_num number;
4 begin
5 execute immediate 'select ' || p_name ||
6 '.nextval from dual' INTO l_num;
7 execute immediate 'alter sequence ' || p_name ||
8 ' increment by ' || (p_val-l_num-1) ||
9 ' minvalue 0';
10 execute immediate 'select ' || p_name ||
11 '.nextval from dual' INTO l_num;
12 execute immediate 'alter sequence ' || p_name ||
13 ' increment by 1 ';
14 dbms_output.put_line
15 ( 'Sequence ' || p_name || ' is now at ' || p_val );
16 end;
17 /
Procedure created.
ops$tkyte@ORA920LAP>
ops$tkyte@ORA920LAP> drop sequence s;
Sequence dropped.
ops$tkyte@ORA920LAP> create sequence s;
Sequence created.
ops$tkyte@ORA920LAP>
ops$tkyte@ORA920LAP> exec set_seq_to( 's', 10032 );
Sequence s is now at 10032
PL/SQL procedure successfully completed.
ops$tkyte@ORA920LAP> select s.nextval from dual;
NEXTVAL
----------
10032
ops$tkyte@ORA920LAP> exec set_seq_to( 's', 1 );
Sequence s is now at 1
PL/SQL procedure successfully completed.
ops$tkyte@ORA920LAP> select s.nextval from dual;
NEXTVAL
----------
1
Then I guess you could always:
begin
for i in (select sequence_name from user_sequences)
loop
set_seq_to(i.sequnce_name, 1);
end loop;
end;
/
Followup May 17, 2005 - 3pm Central time zone:
right, but that is not an entire database, nor schema 'in one go', that is one at a time (thats
what I meant in my head, of course you can loop, but they are discrete independent steps -- maybe I
overparsed that one :)
Need to avoid ORA-04002
May 17, 2005 - 3pm Central time zone
Reviewer: andrew from ca, usa
SQL> CREATE OR REPLACE PROCEDURE set_seq_to (p_name IN VARCHAR2, p_val IN NUMBER)
2 AS
3 l_num NUMBER;
4 BEGIN
5 EXECUTE IMMEDIATE 'select ' || p_name || '.nextval from dual' INTO l_num;
6 EXECUTE IMMEDIATE 'alter sequence ' || p_name || ' increment by ' ||
7 (p_val - l_num - 1)|| ' minvalue 0';
8 EXECUTE IMMEDIATE 'select ' || p_name || '.nextval from dual' INTO l_num;
9 EXECUTE IMMEDIATE 'alter sequence ' || p_name || ' increment by 1 ';
10 DBMS_OUTPUT.put_line ('Sequence ' || p_name || ' is now at ' || p_val);
11 END;
12 /
Procedure created.
SQL> CREATE SEQUENCE s1 START WITH 1;
Sequence created.
SQL> EXEC set_seq_to ('S1', 2);
BEGIN set_seq_to ('S1', 2); END;
*
ERROR at line 1:
ORA-04002: INCREMENT must be a non-zero integer
ORA-06512: at "SOURCE.SET_SEQ_TO", line 6
ORA-06512: at line 1
SQL> DROP SEQUENCE s1;
Sequence dropped.
SQL> CREATE OR REPLACE PROCEDURE set_seq_to (p_name IN VARCHAR2, p_val IN NUMBER)
2 AS
3 l_num NUMBER;
4 BEGIN
5 EXECUTE IMMEDIATE 'select ' || p_name || '.nextval from dual' INTO l_num;
6 -- Added check for 0 to avoid "ORA-04002: INCREMENT must be a non-zero integer"
7 IF (p_val - l_num - 1) != 0 THEN
8 EXECUTE IMMEDIATE 'alter sequence ' || p_name || ' increment by ' ||
9 (p_val - l_num - 1)|| ' minvalue 0';
10 END IF;
11 EXECUTE IMMEDIATE 'select ' || p_name || '.nextval from dual' INTO l_num;
12 EXECUTE IMMEDIATE 'alter sequence ' || p_name || ' increment by 1 ';
13 DBMS_OUTPUT.put_line ('Sequence ' || p_name || ' is now at ' || p_val);
14 END;
15 /
Procedure created.
SQL> CREATE SEQUENCE s1 START WITH 1;
Sequence created.
SQL> EXEC set_seq_to ('S1', 2);
Sequence S1 is now at 2
PL/SQL procedure successfully completed.
Followup May 17, 2005 - 4pm Central time zone:
looks like you did then.
Tom Kyte's patience
May 17, 2005 - 3pm Central time zone
Reviewer: Karthik Kirubakaran from Connecticut, USA
Hi Tom,
I am a great fan of your site, though I have never asked any questions. I enjoy reading it everyday
(marked in my rss feed).
I think you seriously deserve appreciation for your patience in answering questions (many of which
are really very basic and stupid, I dont understand why people just ask question without doing
their homework, they expect you to spoon feed them).
You are great!.
Thanks
Karthik
Followup May 17, 2005 - 4pm Central time zone:
please -- don't call them stupid, no such thing.... really -- we all learn sometime.
Resetting Sequences
October 15, 2008 - 3pm Central time zone
Reviewer: MK from London, UK
Hi Tom,
I have a problem where I have a list of tables and a list of sequences. I fill in these tables with
data and after doing so I want to reset the sequences to the correct next vals. The sequences
usually follow the naming convention of "<table_name>_id_seq" but sometimes the table name is too
large causing the sequence name to be invalid, hence the table name portion in the sequence name is
truncated. I am just wondering if there was a method of RELATING what sequence gets used by which
table in the database? Is there a way to find out exactly which sequence would get used by a table
so I can have a function that takes in the table_name, the sequence name and resets the sequences
accordingly. Right now I assume the sequence will adher to the naming convention as above, but this
works fine for majority of the cases and fails in some instances. Just want a better way of doing
this. Hopefully you can suggest a means.
Thanks in advance!
Followup October 17, 2008 - 7pm Central time zone:
... if there was a method of RELATING what
sequence gets used by which table in the database? ...
no, because there is quite simply no relationship between a sequence and a table.
Unless you used a trigger (bad practice in my opinion) to populate the column automagically. Then, the trigger would be dependent in the table and the sequence - giving you a possible *possible* linkage.
but if you did this in some predicable fashion - eg:
sequence_name = substr( table_name, 1, 23 ) || '_id_seq'
then you would be able to do that, assuming you have no name clashes over 23 characters.
There's another way - "re"cycle it.
March 18, 2009 - 12am Central time zone
Reviewer: George Rypysc from Connecticut, USA
The only problem with "resetting" a sequence by incrementing backwards is, as Tom pointed out, if
nextval is called more than once during the brief time when the sequence is set to go backwards,
other users (or you) get the error:
ORA-08004: sequence SEQ.NEXTVAL goes below MINVALUE and cannot be instantiated
A different "reset" technique avoids that error: Set the sequence to "cycle" immediately back to
the minvalue you need. And then, if you want, remove the cycle and set maxvalue to a larger value
you need for the longterm. For example, to go from 15 back to 3:
10gR2XE> create sequence seq;
Sequence created.
10gR2XE> select seq.nextval from emp;
NEXTVAL
------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
14 rows selected.
10gR2XE> column S new_val max;
10gR2XE> select seq.nextval S from dual;
S
------------
15
10gR2XE> alter sequence seq CYCLE minvalue 3 maxvalue &max cache 10;
old 1: alter sequence seq CYCLE minvalue 3 maxvalue &max cache 10
new 1: alter sequence seq CYCLE minvalue 3 maxvalue 15 cache 10
Sequence altered.
10gR2XE> -- Cache had to be set below default of 20 because
10gR2XE> -- this example uses a small sequence range of
10gR2XE> -- 3 to 15 which is smaller than 20.
10gR2XE> -- Otherwise, it would cause the error:
10gR2XE> -- ORA-04013: number to CACHE must be less than one cycle)
10gR2XE> select seq.nextval S from dual;
S
------------
3
10gR2XE> -- Multiple nextval's here cause no error
10gR2XE> -- unlike the incrementing backwards method.
10gR2XE> select seq.nextval S from dual;
S
------------
4
10gR2XE> select seq.nextval S from dual;
S
------------
5
10gR2XE> -- Now, remove the cycle or make it larger
10gR2XE> -- and be sure to increase maxvalue!
10gR2XE> alter sequence seq NOCYCLE maxvalue 9999999 cache 20;
Sequence altered.
10gR2XE> select seq.nextval S from dual;
S
------------
6
Oracle sequence VS user created
October 9, 2009 - 6am Central time zone
Reviewer: A reader
Hi Tom,
Just interested in hearing your thoughts regarding approach
Using Oracle sequence or creating a table and storing the last used number in it and manually
incrementing it.
I am curious to know if the option of manually creating sequence has any advantage over Oracle
sequences or vice versa.
I would like to know if there is any significant difference between these approaches?
Thank you,
Arch
|