Trying to create a sequence in Oracle that starts with the max value from a specific table. Why does this not work?
CREATE SEQUENCE transaction_sequence
MI
you might want to start with max(trans_seq_no) + 1.
watch:
SQL> create table my_numbers(my_number number not null primary key);
Table created.
SQL> insert into my_numbers(select rownum from user_objects);
260 rows created.
SQL> select max(my_number) from my_numbers;
MAX(MY_NUMBER)
--------------
260
SQL> create sequence my_number_sn start with 260;
Sequence created.
SQL> insert into my_numbers(my_number) values (my_number_sn.NEXTVAL);
insert into my_numbers(my_number) values (my_number_sn.NEXTVAL)
*
ERROR at line 1:
ORA-00001: unique constraint (NEIL.SYS_C00102439) violated
When you create a sequence with a number, you have to remember that the first time you select against the sequence, Oracle will return the initial value that you assigned it.
SQL> drop sequence my_number_sn;
Sequence dropped.
SQL> create sequence my_number_sn start with 261;
Sequence created.
SQL> insert into my_numbers(my_number) values (my_number_sn.NEXTVAL);
1 row created.
If you're trying to do the 'gapless' thing, I strongly advise you to
If you can use PL/SQL, try (EDIT: Incorporates Neil's xlnt suggestion to start at next higher value):
SELECT 'CREATE SEQUENCE transaction_sequence MINVALUE 0 START WITH '||MAX(trans_seq_no)+1||' INCREMENT BY 1 CACHE 20'
INTO v_sql
FROM transaction_log;
EXECUTE IMMEDIATE v_sql;
Another point to consider: By setting the CACHE parameter to 20, you run the risk of losing up to 19 values in your sequence if the database goes down. CACHEd values are lost on database restarts. Unless you're hitting the sequence very often, or, you don't care that much about gaps, I'd set it to 1.
One final nit: the values you specified for CACHE and INCREMENT BY are the defaults. You can leave them off and get the same result.
Bear in mid, the MAX value will only be the maximum of committed values. It might return 1234, and you may need to consider that someone has already inserted 1235 but not committed.
You can't use a subselect inside a CREATE SEQUENCE
statement. You'll have to select the value beforehand.
use dynamic sql
BEGIN
DECLARE
maxId NUMBER;
BEGIN
SELECT MAX(id)+1
INTO maxId
FROM table_name;
execute immediate('CREATE SEQUENCE sequane_name MINVALUE '||maxId||' START WITH '||maxId||' INCREMENT BY 1 NOCACHE NOCYCLE');
END;
END;
Based on Ivan Laharnar with less code and simplier:
declare
lastSeq number;
begin
SELECT MAX(ID) + 1 INTO lastSeq FROM <TABLE_NAME>;
if lastSeq IS NULL then lastSeq := 1; end if;
execute immediate 'CREATE SEQUENCE <SEQUENCE_NAME> INCREMENT BY 1 START WITH ' || lastSeq || ' MAXVALUE 999999999 MINVALUE 1 NOCACHE';
end;