• 强制获取序列下一个值/当前值(oracle函数)


    推荐

    作者:靓仔小伙计

    作者:周公

    oracle创建序列:

    先假设有这么一个表:

    create table S_Depart  (
       DepartId             INT                             not null,
       DepartName           NVARCHAR2(40)                   not null,
       DepartOrder          INT                            default 0,
       constraint PK_S_DEPART primary key (DepartId)
    );

    查看数据库下的所有序列:

    select * from all_sequences

    Oracle中sequence就是所谓的序列号,每次取的时候它会自动增加,一般用在需要按序列号排序的地方。 
    1、Create Sequence 
    你首先要有CREATE SEQUENCE或者CREATE ANY SEQUENCE权限, 
    CREATE SEQUENCE emp_sequence 
    INCREMENT BY 1 -- 每次加几个 
    START WITH 1 -- 从1开始计数 
    NOMAXvalue -- 不设置最大值 
    NOCYCLE -- 一直累加,不循环 
    CACHE 10; --设置缓存cache个序列,如果系统down掉了或者其它情况将会导致序列不连续,也可以设置为---------NOCACHE
    针对S_Depart创建的sequence如下:

    create sequence S_S_DEPART
    minvalue 1
    maxvalue 999999999999999999999999999
    start with 1
    increment by 1
    nocache;

    一旦定义了emp_sequence,你就可以用CURRVAL,NEXTVAL 
    CURRVAL=返回 sequence的当前值 
    NEXTVAL=增加sequence的值,然后返回 sequence 值 
    比如: 
    emp_sequence.CURRVAL 
    emp_sequence.NEXTVAL 
    可以使用sequence的地方: 
    - 不包含子查询、snapshot、VIEW的 SELECT 语句 
    - INSERT语句的子查询中 
    - NSERT语句的valueS中 
    - UPDATE 的 SET中 
    可以看如下例子: 

    insert into S_Depart(departId,Departname,Departorder)values(S_S_Depart.Nextval,'12345',1);
    SELECT empseq.currval FROM DUAL; 

    但是要注意的是: 
    - 第一次NEXTVAL返回的是初始值;随后的NEXTVAL会自动增加你定义的INCREMENT BY值,然后返回增加后的值。CURRVAL 总是返回当前SEQUENCE的值,但是在第一次NEXTVAL初始化之后才能使用CURRVAL,否则会出错。一次NEXTVAL会增加一次 SEQUENCE的值,所以如果你在同一个语句里面使用多个NEXTVAL,其值就是不一样的。明白? 
    - 如果指定CACHE值,oracle就可以预先在内存里面放置一些sequence,这样存取的快些。cache里面的取完后,oracle自动再取一组到cache。 使用cache或许会跳号, 比如数据库突然不正常down掉(shutdown abort),cache中的sequence就会丢失. 所以可以在create sequence的时候用nocache防止这种情况。 
    2、Alter Sequence 
    你或者是该sequence的owner,或者有ALTER ANY SEQUENCE 权限才能改动sequence. 可以alter除start至以外的所有sequence参数.如果想要改变start值,必须 drop sequence 再 re-create . 
    Alter sequence 的例子 

    ALTER SEQUENCE emp_sequence 
    INCREMENT BY 10 
    MAXvalue 10000 
    CYCLE -- 到10000后从头开始 
    NOCACHE ; 

    影响Sequence的初始化参数: 

    SEQUENCE_CACHE_ENTRIES =设置能同时被cache的sequence数目。 

    可以很简单的Drop Sequence 

    DROP SEQUENCE order_seq; 

    一个简单的例子:

    create sequence SEQ_ID
    minvalue 1
    maxvalue 99999999
    start with 1
    increment by 1
    nocache
    order;

    建解发器代码为:

    create or replace trigger tri_test_id
      before insert on S_Depart   --S_Depart 是表名
      for each row
    declare
      nextid number;
    begin
      IF :new.DepartId IS NULLor :new.DepartId=0 THEN --DepartId是列名
        select SEQ_ID.nextval --SEQ_ID正是刚才创建的
        into nextid
        from sys.dual;
        :new.DepartId:=nextid;
      end if;
    end tri_test_id;

    OK,上面的代码就可以实现自动递增的功能了。

    获取sequence序列的值:

    create or replace function get_seq_next (seq_name in varchar2) return number
    is
      seq_val number ;
    begin
      execute immediate 'select '|| seq_name|| '.nextval from dual' into seq_val ;
      return seq_val ;
    end get_seq_next;
    -- 创建获取序列下一个值的函数(得先获取下一个值后才能使用)
    create or replace function get_seq_curr (seq_name in varchar2) return number
    is
      seq_val number ;
    begin
      execute immediate 'select '|| seq_name|| '.currval from dual' into seq_val ;
      return seq_val ;
    end get_seq_curr;

    ORACLE实现自定义序列号生成

    实际工作中,难免会遇到序列号生成问题,下面就是一个简单的序列号生成函数

    (1)创建自定义序列号配置表如下:

    --自定义序列
    create table S_AUTOCODE
    (
      pk1           VARCHAR2(32) primary key,
      atype         VARCHAR2(20) not null,
      owner         VARCHAR2(10) not null,
      initcycle     CHAR(1) not null,
      cur_sernum    VARCHAR2(50) not null,
      zero_flg      VARCHAR(2) not null,
      sequencestyle VARCHAR2(50),
      memo          VARCHAR2(60)
    );
    -- Add comments to the columns 
    comment on column S_AUTOCODE.pk1  is '主键';
    comment on column S_AUTOCODE.atype  is '序列号类型';
    comment on column S_AUTOCODE.owner  is '序列号所有者';
    comment on column S_AUTOCODE.initcycle  is '序列号递增';
    comment on column S_AUTOCODE.cur_sernum  is '序列号';
    comment on column S_AUTOCODE.zero_flg  is '序列号长度';
    comment on column S_AUTOCODE.sequencestyle  is '序列号样式';
    comment on column S_AUTOCODE.memo  is '备注';
    -- Create/Recreate indexes 
    create index PK_S_AUTOCODE on S_AUTOCODE (ATYPE, OWNER);

    (2)初始化配置表,例如:

    (3)自定义序列号生成函数:

    创建函数:SF_SYS_GEN_AUTOCODE
    CREATE OR REPLACE FUNCTION SF_SYS_GEN_AUTOCODE(
              I_ATYPE IN VARCHAR2,  /*序列类别*/
              I_OWNER IN VARCHAR2   /*序列所有者*/
    ) RETURN VARCHAR2 IS
            /**************************************************************************************************/
            /* PROCEDURE NAME : SF_SYS_GEN_AUTOCODE                                                           */
            /* DEVELOPED BY   : WANGXF                                                                        */
            /* DESCRIPTION    : 主要用来生成自定义的序列号                                                    */                   
            /* DEVELOPED DATE : 2016-10-08                                                                    */
            /* CHECKED BY     :                                                                               */
            /* LOAD METHOD    : F1-DELETE INSERT                                                              */
            /**************************************************************************************************/
    
           O_AUTOCODE VARCHAR2(100);                        /*输出的序列号*/
           V_INITCYCLE S_AUTOCODE.INITCYCLE%TYPE;       /*序列号递增*/
           V_CUR_SERNUM S_AUTOCODE.CUR_SERNUM%TYPE;     /*序列号*/
           V_ZERO_FLAG S_AUTOCODE.ZERO_FLG%TYPE;        /*序列号长度*/
           V_SEQUENCESTYLE S_AUTOCODE.SEQUENCESTYLE%TYPE;/*序列号样式*/
           V_SEQ_NUM VARCHAR2(100);                     /*本次序列号*/
           V_DATE_YEAR CHAR(4);                         /*年份,如2016*/
           V_DATE_YEAR_MONTH CHAR(6);                   /*年份月份,如201610*/
           V_DATE_DATE CHAR(8);                         /*年份月份日,如20161008*/
           V_DATE_DATE_ALL CHAR(14);                    /*完整年份序列,如20161008155732*/
           
           /*
              支持的参数序列:
              $YEAR$ --> 年份
              $YEAR_MONTH$ --> 年份+月份,不含汉子
              $DATE$ --> 年份+月份+日期,不含汉子
              $DATE_ALL$ --> 完整日期,不含汉子
              $ORGAPP$ --> 所有者
              $SER$ --> 当前序列号
           */
           
           --解决查询事务无法执行DML的问题
           Pragma Autonomous_Transaction;
    BEGIN
           -- 查询复核条件的序列号配置
           SELECT T.INITCYCLE,
                  T.CUR_SERNUM, 
                  T.ZERO_FLG,
                  T.SEQUENCESTYLE 
                  INTO V_INITCYCLE,V_CUR_SERNUM,V_ZERO_FLAG,V_SEQUENCESTYLE
           FROM S_AUTOCODE T WHERE T.ATYPE=I_ATYPE AND T.OWNER=I_OWNER ;
           
           --格式化当前日期
           SELECT
                TO_CHAR(SYSDATE,'yyyy'),
                TO_CHAR(SYSDATE,'yyyyMM'),
                TO_CHAR(SYSDATE,'yyyyMMdd'),
                TO_CHAR(SYSDATE,'yyyyMMddHH24MISS')
                INTO  V_DATE_YEAR,V_DATE_YEAR_MONTH,V_DATE_DATE,V_DATE_DATE_ALL
           FROM DUAL;
           
           -- 日期处理
           O_AUTOCODE := REPLACE(V_SEQUENCESTYLE,'$YEAR$',V_DATE_YEAR);
           O_AUTOCODE := REPLACE(O_AUTOCODE,'$YEAR_MONTH$',V_DATE_YEAR_MONTH);
           O_AUTOCODE := REPLACE(O_AUTOCODE,'$DATE$',V_DATE_DATE);
           O_AUTOCODE := REPLACE(O_AUTOCODE,'$DATE_ALL$',V_DATE_DATE_ALL);
           
           --所有者处理
           O_AUTOCODE := REPLACE(O_AUTOCODE,'$ORGAPP$',I_OWNER);
            
           --序号处理
           V_SEQ_NUM := TO_CHAR(TO_NUMBER(V_CUR_SERNUM)+TO_NUMBER(V_INITCYCLE));
           
           --反写当前序列号,确保每次都是递增
           UPDATE S_AUTOCODE T SET T.CUR_SERNUM=V_SEQ_NUM WHERE T.ATYPE=I_ATYPE AND T.OWNER=I_OWNER ;
           
           --不满足长度的前面补0
           IF LENGTH(V_SEQ_NUM) < TO_NUMBER(V_ZERO_FLAG)
             THEN
          /*
               LOOP 
                 V_SEQ_NUM := '0'||V_SEQ_NUM;
               EXIT WHEN LENGTH(V_SEQ_NUM) = TO_NUMBER(V_ZERO_FLAG);
               END LOOP;
          */
           V_SEQ_NUM := LPAD(V_SEQ_NUM,TO_NUMBER(V_ZERO_FLAG),'0');
           END IF;
              
           O_AUTOCODE := REPLACE(O_AUTOCODE,'$SER$',V_SEQ_NUM);
           
           COMMIT;
           RETURN O_AUTOCODE;
    EXCEPTION 
           --如果没有对应的配置项,则返回ERROR值
           WHEN NO_DATA_FOUND THEN
             ROLLBACK;
             DBMS_OUTPUT.put_line('there is no config as you need...');
             RETURN 'ERROR';
    END SF_SYS_GEN_AUTOCODE;

    (4)测试:

    配置项:$YEAR$年$ORGAPP$质字第$SER$号
    SELECT SF_SYS_GEN_AUTOCODE('ZDBCONTCN','012805') FROM DUAL;

    (5) 结果

    2016年012805质字第0200001号
  • 相关阅读:
    可爱的中国电信 请问我们的电脑还属于我们自己吗?
    了解客户的需求,写出的代码或许才是最优秀的............
    DELPHI DATASNAP 入门操作(3)简单的主从表的简单更新【含简单事务处理】
    用数组公式获取字符在字符串中最后出现的位置
    在ehlib的DBGridEh控件中使用过滤功能(可以不用 MemTableEh 控件 适用ehlib 5.2 ehlib 5.3)
    格式化json返回的时间
    ExtJs中使用Ajax赋值给全局变量异常解决方案
    java compiler level does not match the version of the installed java project facet (转)
    收集的资料(六)ASP.NET编程中的十大技巧
    收集的资料共享出来(五)Asp.Net 权限解决办法
  • 原文地址:https://www.cnblogs.com/lxl57610/p/7439614.html
Copyright © 2020-2023  润新知