【Oracle】仿Oracle Sequence的自定义年份Sequence(适合任何数据库)(续)

在《仿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,就可以为所有类似方式的年份流水号公用一个表,不必每种流水号都要建表盒函数;甚至还可以根据实际情况添加字段,把所有的复合流水号管理起来。到那个时候要注意一点,必须建好索引。

posted @ 2011-10-28 16:22  泥头  阅读(305)  评论(0编辑  收藏  举报