47

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
  MINVALUE 0
  START WITH (SELECT MAX(trans_seq_no)
     FROM TRANSACTION_LOG) 
  INCREMENT BY 1
  CACHE 20;
Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
Amar Premsaran Patel
  • 1,293
  • 7
  • 17
  • 26

8 Answers8

39

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.

Joel Beckham
  • 18,254
  • 3
  • 35
  • 58
DCookie
  • 42,630
  • 11
  • 83
  • 92
32

Here I have my example which works just fine:

declare
 ex number;
begin
  select MAX(MAX_FK_ID)  + 1 into ex from TABLE;
  If ex > 0 then
    begin
            execute immediate 'DROP SEQUENCE SQ_NAME';
      exception when others then
        null;
    end;
    execute immediate 'CREATE SEQUENCE SQ_NAME INCREMENT BY 1 START WITH ' || ex || ' NOCYCLE CACHE 20 NOORDER';
  end if;
end;
  • This works great! @united-exression this is how you can automate it. It should be the accepted answer. I don't know why a non-answer is the accepted answer... – ADTC Nov 22 '15 at 16:51
20

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

1 not do it, and #2 not use a sequence for it.

Community
  • 1
  • 1
Neil Kodner
  • 2,901
  • 3
  • 27
  • 36
  • +1 for the the catch on starting point of sequence. Also, I have to assume if he's setting the CACHE parameter to anything other than 1, he's not concerned about gaps! – DCookie Apr 29 '09 at 20:21
  • 2
    i was going to mention the cache being low but thought that was outside the scope of the question. Now if the user is expecting gapless numbers, by way of a sequence, they've got another things coming. Rollback doesn't 'decrement' a sequence ;) – Neil Kodner Apr 30 '09 at 00:38
  • 1
    Hmm, that advice in bold at the bottom calls for an alternative approach and/or an explanation... – Lukas Eder May 30 '14 at 07:31
  • 4
    While this is useful info (pointing out a mistake in the asker's approach), this is not an answer to the question. Sorry to say that, but this shouldn't be the accepted solution. The actual answer that worked for me is Ivan's. – ADTC Nov 22 '15 at 16:52
19

You can't use a subselect inside a CREATE SEQUENCE statement. You'll have to select the value beforehand.

Chad Birch
  • 73,098
  • 23
  • 151
  • 149
13

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.

Gary Myers
  • 34,963
  • 3
  • 49
  • 74
  • 1
    +1 for pointing out the race condition. All this is really only safe if you make sure no one is writing to the DB at the same time. – sleske Dec 09 '11 at 11:08
8

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;
dmonti
  • 448
  • 4
  • 13
2
DECLARE
    v_max NUMBER;
BEGIN
    SELECT (NVL (MAX (<COLUMN_NAME>), 0) + 1) INTO v_max FROM <TABLE_NAME>;
    EXECUTE IMMEDIATE 'CREATE SEQUENCE <SEQUENCE_NAME> INCREMENT BY 1 START WITH ' || v_max || ' NOCYCLE CACHE 20 NOORDER';
END;
evandertino
  • 358
  • 1
  • 3
0

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;
Samir Ghoneim
  • 591
  • 1
  • 6
  • 14