如何在Oracle 10g中每年自动将序列值重置为0?

tth*_*tth 6 sql oracle

在问题中,如何在Oracle 10g中每年自动将Oracle序列的值重置为0?

我正在使用序列生成格式的标识符,YYYY<sequence value>并且序列值必须每年重置为0.

YYYY从Java获取并与Oracle的序列值连接.由于外部第三方要求,无法更改标识符的格式.在此先感谢您的帮助.

spe*_*593 6

序列并非真正设计为重置.但是在某些情况下需要重置序列,例如,在设置测试数据或将生产数据合并回测试环境时.这种类型的活动通常不在生产中完成.

如果这种类型的操作将投入生产,则需要进行全面测试.(引起最大关注的是在一年中错误的时间意外执行重置程序的可能性.

删除和重新创建序列是一种方法.作为一项操作,就SEQUENCE而言,它是相当简单的:

    DROP SEQUENCE MY_SEQ;
    CREATE SEQUENCE MY_SEQ START WITH 1 INCREMENT BY 1 MINVALUE 0;

[编辑]正如Matthew Watson正确指出的那样,每个DDL语句(例如DROP,CREATE,ALTER)都将导致隐式提交.[/编辑]

但是,SEQUENCE上授予的任何权限都将被删除,因此需要重新授予这些权限.引用序列的任何对象都将失效.为了更加通用化,您需要保存权限(在删除序列之前),然后重新授予它们.

第二种方法是改变现有的SEQUENCE,而不是丢弃并重新创建它.重置序列可以通过增量值改变为负值(电流值和0之间的差)来实现,然后执行正好一个.NEXTVAL到的电流值设置为0,然后更改INCREMENT回到1.我之前(手动地,在测试环境中)使用了相同的方法来将序列设置为更大的值.

当然,为了使其正常工作,您需要确保在执行此操作时没有其他会话引用该序列.在错误的瞬间额外的.NEXTVAL会搞砸重置.(注意:如果应用程序是作为序列的所有者连接而不是作为单独的用户连接,那么在数据库端实现这一点将很困难.)

为了让它每年都发生,你需要安排一份工作.序列重置必须与标识符的YYYY部分重置相协调.

这是一个例子:

http://www.jaredstill.com/content/reset-sequence.html

[编辑]

UNTESTED占位符,用于重置序列的PL/SQL块的一种可能设计

    declare
      pragma autonomous_transaction;
      ln_increment       number;
      ln_curr_val        number;
      ln_reset_increment number;
      ln_reset_val       number;
    begin

      -- save the current INCREMENT value for the sequence
      select increment_by
        into ln_increment
        from user_sequences
       where sequence_name = 'MY_SEQ';

      -- determine the increment value required to reset the sequence
      -- from the next fetched value to 0
      select -1 - MY_SEQ.nextval into ln_reset_increment from dual;

      -- fetch the next value (to make it the current value)
      select MY_SEQ.nextval into ln_curr from dual;

      -- change the increment value of the sequence to 
      EXECUTE IMMEDIATE 'alter sequence MY_SEQ increment by '
        || ln_reset_increment ||' minvalue 0';

      -- advance the sequence to set it to 0
      select MY_SEQ.nextval into ln_reset_val from dual;

      -- set increment back to the previous(ly saved) value
      EXECUTE IMMEDIATE 'alter sequence MY_SEQ increment by '
        || ln_increment ;
    end;
    /

笔记:

  • 如何最好地保护序列在重置时不被访问,重命名呢?
  • 几个测试用例在这里工作.
  • 第一遍,检查正,升,增1序列的规范情况.
  • 更好的方法是创建新的SEQUENCE,添加权限,重命名现有和新的序列,然后重新编译依赖项?


Jef*_*emp 5

把它扔出去作为一个想法:

如果你想要一个不需要持续DDL的解决方案(即没有丢弃和创建或重置序列),甚至任何工作,你可以考虑这样的事情(这只是原则上,我没有测试过这种方法,但我是确定它会工作):

  1. 创建单个序列.

  2. 创建一个参考表,每年一行,例如

    年(年份数(4,0)PRIMARY KEY,starting_value NUMBER)

  3. 当您NEXTVAL从序列中获得时,您必须starting_value从YEARS表中查询当前年份.如果未找到年份,则应插入新行(即,在任何给定年份中运行的第一个流程将插入新值).

例如,一个函数,例如get_year_starting_value (pn_year IN NUMBER) RETURN NUMBER可以查询该表并返回starting_value给定年份; 如果它得到NO_DATA_FOUND,它可以调用一个过程来使用NEXTVAL序列中的插入(在自治事务中提交,以便新值立即可用于其他会话,并且因此该函数不会因副作用而失败)

可能不是所有情况的解决方案,但我认为这种方法可能至少在某些情况下有所帮助.

  • 是.YEARS表上的主键约束将有效地序列化对表的访问,而这只会每年发生一次 - 该过程需要适当地处理DUP_VAL_ON_INDEX异常.自治事务的想法只是为了避免影响调用事务的提交. (2认同)