【问题标题】:How to create an Oracle sequence starting with max value from a table?如何从表中创建以最大值开始的 Oracle 序列?
【发布时间】:2009-04-28 16:23:23
【问题描述】:

尝试在 Oracle 中创建一个以特定表中的最大值开始的序列。为什么这不起作用?

CREATE SEQUENCE transaction_sequence
  MINVALUE 0
  START WITH (SELECT MAX(trans_seq_no)
     FROM TRANSACTION_LOG) 
  INCREMENT BY 1
  CACHE 20;

【问题讨论】:

    标签: sql oracle sequence


    【解决方案1】:

    如果您可以使用 PL/SQL,请尝试(编辑:结合 Neil 的 xlnt 建议从下一个更高的值开始):

    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;
    

    要考虑的另一点:通过将 CACHE 参数设置为 20,如果数据库出现故障,您可能会在序列中丢失多达 19 个值。缓存的值在数据库重新启动时丢失。除非你经常打这个序列,或者你不太关心间隔,我会把它设置为 1。

    最后一点:您为 CACHE 和 INCREMENT BY 指定的值是默认值。您可以不使用它们并获得相同的结果。

    【讨论】:

      【解决方案2】:

      我的例子很好用:

      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;
      

      【讨论】:

      • 这很好用! @united-exression 这就是您可以自动化它的方式。它应该是公认的答案。我不知道为什么非答案是公认的答案...
      【解决方案3】:

      你可能想从max(trans_seq_no) + 1.开始

      观看:

      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
      

      当您创建一个带有数字的序列时,您必须记住,当您第一次选择该序列时,Oracle 将返回您分配给它的初始值。

      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.
      

      如果你想做“无缝”的事情,我强烈建议你这样做

      1 不做,#2 不使用序列。

      【讨论】:

      • +1 表示序列的起始点。另外,我必须假设如果他将 CACHE 参数设置为 1 以外的任何值,他并不关心间隙!
      • 我要提到缓存很低,但认为这超出了问题的范围。现在,如果用户期待无间隔的数字,通过一个序列,他们就会得到另一件事。回滚不会“减少”序列;)
      • 嗯,底部粗体字的建议需要另一种方法和/或解释......
      • 虽然这是有用的信息(指出提问者方法中的错误),但这不是问题的答案。很抱歉这么说,但这不应该是公认的解决方案。对我有用的实际答案是 Ivan 的。
      • 这是对该问题的有效评论,但绝对不是答案。
      【解决方案4】:

      您不能在CREATE SEQUENCE 语句中使用子选择。您必须事先选择值。

      【讨论】:

      • 是的 - 但是有没有人有一个简单的替代方案来自动化这个?
      【解决方案5】:

      在中间承受,MAX 值只会是承诺值的最大值。它可能会返回 1234,您可能需要考虑到有人已经插入了 1235 但尚未提交。

      【讨论】:

      • +1 用于指出竞争条件。所有这一切只有在确保没有人同时写入数据库时​​才真正安全。
      【解决方案6】:

      基于 Ivan Laharnar,代码更少,更简单:

      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;
      

      【讨论】:

      • 不错。如果还没有行,我只会在 select 和 execute 之间添加以下行:if lastSeq is null then lastSeq := 0; end if;
      • 不错的例子,但我的脚本重新创建了序列,因为我已经加入了脚本。
      【解决方案7】:
      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;
      

      【讨论】:

        【解决方案8】:

        使用动态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;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-01-27
          • 2016-06-01
          • 2013-03-04
          • 1970-01-01
          • 1970-01-01
          • 2015-01-16
          • 1970-01-01
          相关资源
          最近更新 更多