在《仿Oracle Sequence的自定义年份Sequence(适合任何数据库)》中(http://www.cnblogs.com/litou/articles/1689655.html)建立表和函数的方法模拟Sequence,效果确实不错,但还有点不足,就是需要初始化很多年份数据,尽管很少情况下用完,但何不改造成完全自动增加呢?
自动增加的原理,就是在表中保存一条模板记录,当当前年份记录不存在时,从模板记录中复制出来并修改为当前年份,问题迎刃而解。
原表接口和仿CurrVal函数不变(请参考上一篇文章),仿NextVal函数需要修改:
create or replace function IDNextval return number is
PRAGMA AUTONOMOUS_TRANSACTION; --Oracle函数中需要添加此参数才能在函数中执行SQL
Result Number;
lYear number;
lCount number;
cursor idsequence_cursor(nYear in varchar2) is select * from idsequence where year=nYear;
refidsequence idsequence_cursor%rowtype;
begin
lYear := to_char(sysdate, 'yyyy');
Result := -1;
--当前年份无记录,从year=0模板复制
select count(1) into lCount from idsequence where year=lYear;
if lCount = 0 then
select count(1) into lCount from idsequence where year=0;
if lCount = 1 then
insert into idsequence(year, minvalue, maxvalue, nextnumber, increaseby, cycle) select lYear, minvalue, maxvalue, nextnumber, increaseby, cycle from idsequence where year=0;
commit;
end if;
end if;
--获取值
open idsequence_cursor(lYear);
fetch idsequence_cursor into refidsequence;
if idsequence_cursor%found then
Result := refidsequence.nextnumber;
if refidsequence.nextnumber >= refidsequence.minvalue then --当前值大于等于最小值
if refidsequence.nextnumber >= refidsequence.maxvalue then --当前值大于等于最大值
if refidsequence.cycle = 1 then --循环则当前值等于最小值
update idsequence set nextnumber=minvalue where year=lYear;
else --不循环则当前值为最小值-1,即无效值
update idsequence set nextnumber=minvalue-1 where year=lYear;
end if;
else --当前值大于等于最小值小于最大值
if refidsequence.nextnumber+refidsequence.increaseby > refidsequence.maxvalue then --当前值加增量大于最大值
update idsequence set nextnumber=minvalue where year=lYear;
else
update idsequence set nextnumber=nextnumber+refidsequence.increaseby where year=lYear;
end if;
end if;
commit;
end if;
end if;
close idsequence_cursor;
return(Result);
end IDNextval;
这里指定了year为0的记录为模板记录,可根据实际情况修改。
后话:自定义Sequence确实很方便,以上方法只是抛砖引肉,还可以进行改造和深化,如可在表中添加字段Type,就可以为所有类似方式的年份流水号公用一个表,不必每种流水号都要建表盒函数;甚至还可以根据实际情况添加字段,把所有的复合流水号管理起来。到那个时候要注意一点,必须建好索引。