在问题中,如何在Oracle 10g中每年自动将Oracle序列的值重置为0?
我正在使用序列生成格式的标识符,YYYY<sequence value>并且序列值必须每年重置为0.
YYYY从Java获取并与Oracle的序列值连接.由于外部第三方要求,无法更改标识符的格式.在此先感谢您的帮助.
序列并非真正设计为重置.但是在某些情况下需要重置序列,例如,在设置测试数据或将生产数据合并回测试环境时.这种类型的活动通常不在生产中完成.
如果这种类型的操作将投入生产,则需要进行全面测试.(引起最大关注的是在一年中错误的时间意外执行重置程序的可能性.
删除和重新创建序列是一种方法.作为一项操作,就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;
/
笔记:
把它扔出去作为一个想法:
如果你想要一个不需要持续DDL的解决方案(即没有丢弃和创建或重置序列),甚至任何工作,你可以考虑这样的事情(这只是原则上,我没有测试过这种方法,但我是确定它会工作):
创建单个序列.
创建一个参考表,每年一行,例如
年(年份数(4,0)PRIMARY KEY,starting_value NUMBER)
当您NEXTVAL从序列中获得时,您必须starting_value从YEARS表中查询当前年份.如果未找到年份,则应插入新行(即,在任何给定年份中运行的第一个流程将插入新值).
例如,一个函数,例如get_year_starting_value (pn_year IN NUMBER) RETURN NUMBER可以查询该表并返回starting_value给定年份; 如果它得到NO_DATA_FOUND,它可以调用一个过程来使用NEXTVAL序列中的插入(在自治事务中提交,以便新值立即可用于其他会话,并且因此该函数不会因副作用而失败)
可能不是所有情况的解决方案,但我认为这种方法可能至少在某些情况下有所帮助.
| 归档时间: |
|
| 查看次数: |
27934 次 |
| 最近记录: |