我现有一个流水号要生成,是系统当天日期+4位流水号,形如 200906150001 ,多用户环境使用,30台客户端,要求绝不能重复。请大家帮我写个存储过程,因为我自己对存储过程不熟悉。   从网上看了一些,多是SQLSERVER的。 谢谢!

解决方案 »

  1.   

    ORACLE中生成流水号 创建一个序列:
      create sequence EXAMPLE_SEQ
      increment by 1
      start with 1
      minvalue 1
      cache 20;
      在EXAMPLE表上创建一个触发器
      CREATE OR REPLACE TRIGGER "PORTAL".TRI_EXAMPLE_TABLE BEFORE INSERT ON EXAMPLE_TABLE FOR EACH ROW
      begin
       select to_char(sysdate,'YYYYMMDD')||to_char(EXAMPLE_SEQ.nextval,'0000') into :new.EXAMPLE_ID from dual;
      end;
      

  2.   


    --写一个函数
    --建立表结构
    create table tb(id varchar(30));--写一个函数
    create or replace function GETID
    return varchar2
    is
      Result varchar2(100);
      istr varchar2(100);
      i int;
    begin
       
      select max(id) into istr from tb where substr(id,1,8)=to_char(sysdate,'yyyymmdd');
      
      if istr is null then 
      select to_char(sysdate,'yyyymmdd')||'0001' into Result from dual;
      else
      Result:=substr(istr,1,8);
      
      i:=substr(istr,9,4);
      i:=i+1;
      istr:='00000'||to_char(i);
      istr:=substr(istr,length(istr)-4,length(istr));
      
      Result:=Result||istr;
      
      end if;
      
      return(Result);
    end GETID;--查询函数返回值
    select getid as id from dual;
      

  3.   

    --不过每天夜里0:0:0要把那个序列重置
    请问怎么实现呢? 我虽用ORACELE多年仍菜鸟,不要笑我啊。
      

  4.   

    写个job(pl/sql很容易写的) 在规定时间删除了,再重建
      

  5.   

    上面  ojuju10这位写的函数function GETID,能防止重复值出现吗? 因为许多台客户端一起操作
      

  6.   

    “写个job(pl/sql很容易写的) 在规定时间删除了,再重建 ”
    帮忙说得清楚些啊,  
    我是WIN2003SERVER,以前想让ORACEL定时做某事,是写个批处理,它让执行一个SQL文件,再把它加在计划任务中,不知ORACEL本身的JOB怎么用。另外,因是政府机关的服务器,有时会关机,比如周六、日。周一早上再开   “每天夜里0:0:0要把那个序列重置 ” ,那样的话周一的序列号是不是就不符合要求了? 
      

  7.   

    ------> 包头
    CREATE OR REPLACE PACKAGE MY_SEQUENCE AS
      V_SEQ_VALUE INTEGER := 0;
      PROCEDURE NEW_SEQ_VALUE(SEQ_VALUE OUT INTEGER);
    END MY_SEQUENCE;
    /
    ------> 包体
    CREATE OR REPLACE PACKAGE BODY MY_SEQUENCE AS
      PROCEDURE NEW_SEQ_VALUE(SEQ_VALUE OUT INTEGER) IS
      BEGIN
        IF MY_SEQUENCE.V_SEQ_VALUE = 0
           OR SUBSTR(TO_CHAR(MY_SEQUENCE.V_SEQ_VALUE),
                     1,
                     8) < TO_CHAR(SYSDATE,
                                    'YYYYMMDD')
        THEN
          MY_SEQUENCE.V_SEQ_VALUE := TO_NUMBER(TO_CHAR(SYSDATE,
                                                       'YYYYMMDD') || '0001');
        ELSE
          MY_SEQUENCE.V_SEQ_VALUE := MY_SEQUENCE.V_SEQ_VALUE + 1;
        END IF;
        SEQ_VALUE := MY_SEQUENCE.V_SEQ_VALUE;
      END NEW_SEQ_VALUE;END MY_SEQUENCE;
    ----- > 测试
    DECLARE
      V_VALUE INTEGER;
    BEGIN
      FOR V_I IN 1 .. 10
      LOOP
        MY_SEQUENCE.NEW_SEQ_VALUE(V_VALUE);
        DBMS_OUTPUT.PUT_LINE(TO_CHAR(V_VALUE));
      END LOOP;
    END;
     
      

  8.   


    可以先drop掉sequence,在重建sequence
      

  9.   

    用sequence 感觉太麻烦了,还不如写个函数
      

  10.   

    上面 ojuju10 写的function GETID函数,并没有把 +1后的值写回到那表里的语句啊suncrafted 的包体里也没有把 MY_SEQUENCE.V_SEQ_VALUE := MY_SEQUENCE.V_SEQ_VALUE + 1; 后的新 MY_SEQUENCE.V_SEQ_VALUE存到某个地方啊,多个客户端先后取值时不就一直都取得的是 日期+0001 了? 还是我没看懂啊? 
      

  11.   

    刚写了一个create or replace function fn_no_make(
                                          v_type varchar2,
                                          V_number_col VARCHAR2,
                                          V_Table_Name VARCHAR2)
    return varchar2 
    IS
    /*****************************************************************************
    *                                                                            *
    *   PROGRAM-ID  : fn_no_make                                                 *
    *                                                                            *
    *   DESCRIPTION : make asset,purchase no                                     *
    *                                                                            *
    *                                                                            *
    *   PARAMETER                                                                *
    *                                                                            *
    *       INPUT   : NULL                                                       *
    *                                                                            *
    *       OUTPUT  : NULL                                                       *
    *                                                                            *
    *       LOG     : NULL                                                       *
    ******************************************************************************
    *                                                                            *
    *                                                                            *
    ******************************************************************************/
      V_Maked_No           varchar2(50);    
      v_sql                VARCHAR2(4000);                                                 
    begin
       v_sql := 'select no_init || max_no ';
       v_sql := v_sql || 'from  (select '''|| v_type ||''' || substr(TO_CHAR(SYSDATE,''yyyymmdd''), 1, 8) no_init, ';
       v_sql := v_sql || 'case when SUBSTR(decode(MAX('||V_number_col||'),null,''19000101''),3,8) <> substr(TO_CHAR(SYSDATE,''yyyymmdd''), 1, 8) then ''001'' ';
       v_sql := v_sql || 'ELSE lpad((to_number(SUBSTR(max('||V_number_col||'), 11, 3))+1),3,0)  end max_no  from '||V_Table_Name||') A'
              ;
        execute immediate v_sql INTO V_Maked_No; 
      return(V_Maked_No);
    EXCEPTION
      WHEN OTHERS THEN
      dbms_output.put_line(SQLERRM);
    end fn_no_make;调用Asset_No = cf.Fn_No_Make("AT", "ASM_ASSET_NO", "TB_ASSET_MASTER");结果AT20090616001
      

  12.   

    我没看懂hotyxm写的 function fn_no_make啊,没看见这里面把结果保存在何处啊,即没有用表也没有用序列号,那不同的机器取值时恐怕都是取得的是同一个值吧?
      

  13.   


    拼动态sql的地方没有看清楚,好像是从max拿数据出来再处理的吧 这样并发的情况下,会有同号的情况出现吧