zoukankan      html  css  js  c++  java
  • oracle 顺序号生成函数。仿Sequence

    问题提出自项目中的老代码:一个Bill表,存储所有的表单信息,比如:员工入职单,离职单等等。(别喷,我知道要分多个表。但领导的意愿你是没办法违背的)表单的单据号是以四个字母+年月日+数字顺序号来表示。每次取新单据号时要从Bill表里(按生成规则)查询出最大的那个单据号,再拆分出来,再给顺序号加1,组合好后再写回。哈哈这就是老代码。

    随着软件行业的进步,各种技巧层出不穷。而针对顺序号生成的方法也有好巨大改进。

    [Oracle]仿Oracle Sequence的自定义年份Sequence(适合任何数据库)

    这里其中的一篇。看过这个之后就想自己动手也写一个。于是:

    顺序号表

    --id序列表
    create table SEQUENCES
    (
      id           VARCHAR2(20) not NULL PRIMARY KEY,--标识
      minvalue     NUMBER default 1,--最小值
      maxvalue     NUMBER default 9999999999999999999999999999,--最大值
      currentvalue NUMBER DEFAULT 1,--当前值
      increaseby   NUMBER default 1,--增量
      CYCLE        CHAR(1) default '0' --是否循环
    )

    生成函数

    --获取 select NextValue('abc') from dual;
    create or replace function NextValue(arg varchar2) return number IS
      PRAGMA AUTONOMOUS_TRANSACTION;
      Result number;
      x NUMBER;
      a NUMBER;
      i NUMBER;
      c Char(1);
    BEGIN
      IF TRIM(arg) IS NULL THEN--防止值入空字符串
         RAISE_Application_Error(-6502,'param "arg" is not valide.',TRUE);
      END IF;
    <<top>>
      SELECT COUNT(1) INTO x FROM Sequences WHERE ID = arg;
       IF x = 0 THEN
       BEGIN
          BEGIN
            INSERT INTO Sequences (ID) VALUES(arg);--防止并发同时插入相同的Id值。需要将id设为主键
          EXCEPTION
            WHEN OTHERS THEN
              GOTO top;
          END;
          COMMIT;
          RETURN 1;
       END;
       ELSE
       BEGIN
         SELECT s.currentvalue + s.increaseby,s.maxvalue,s.minvalue,s.cycle INTO Result,a,i,c FROM  Sequences s WHERE ID = arg FOR update;--for update将锁定此行记录
         IF RESULT < a THEN--未超出最大值
         BEGIN
           UPDATE Sequences SET currentvalue = Result WHERE ID = arg;
           COMMIT;
           return(Result);
         END;
         ELSE
         BEGIN
           IF c = '0' THEN--不循环
           BEGIN
              RAISE_Application_Error(-6502,'out of range.',TRUE);
           END;
           ELSE
           BEGIN--循环
              UPDATE Sequences SET currentvalue = i WHERE ID = arg;
              COMMIT;
              RETURN i;
           END;
           END IF;
         END;
         END IF;
       END;
       END IF;
    END;

    是的,我使用了参数。这样就使得这个表更加有用,而非只单独处理一种类型顺序号。同时对并发进行了处理。让你只可能取得一个值,而不会出现重复的值。当然所有的result都没有进行格式化,而是直接输出。在PLSQL中进行函数test,打开两个窗口,单步调试,可以看到在insert或select for update时都会阻塞其它session对此表的操作。这样可以使用result的结果唯一。

  • 相关阅读:
    权限管理的三级菜单的流程
    Django之extra
    Django-Rest-Framework的解析器和渲染器
    Django-Rest-Framework的权限和频率
    权限管理-一级菜单-二级菜单-三级菜单-路径导航和权限粒度控制到按钮级别
    Django-Rest-Framework的版本和认证
    【leetcode】Valid Number
    【leetcode】4Sum
    【leetcode】Preimage Size of Factorial Zeroes Function
    【leetcode】Champagne Tower
  • 原文地址:https://www.cnblogs.com/jara/p/4027543.html
Copyright © 2011-2022 走看看