为什么一个存储过程为什么要写几个begin...end;语句??一个不就行了吗??
写几个与写一个不同吗?
比如下个过程:CREATE OR REPLACE PROCEDURE yfgl_ypkctj(
                                     as_yfbm     in varchar2,    -- 药房编码、药房部门ID
                                     al_xlh      in long,        --入库明细系列号
                                     as_tjdh     in varchar2 ,   --新调价单号
                                     adt_now     in date  ,      --调价日期
                                     ad_xsj      in decimal,     --新药库零售价
                                     ad_sl       in decimal,     --库存数量
                                     as_machine  in varchar2 ,   --机器名
                                     as_yy       in varchar2 ,
                                     as_czy       in varchar2 ,  --操作员
                                     as_bz       in varchar2 ,   --标志
                                     os_retmsg    out varchar2,  --错误信息
                                     oi_return    out integer    --返回值
                                     -- 返回值:
                                     -- 0 --------
                                     --  1 --------
                                     -- -1 --------sql语句执行失败,回滚减库存的事务
                                     -- -2 --------非sql错误
                                     ) isifzb varchar2(1);
gmp varchar2(1);
lsdj number(16,10);
mrdj number(16,10);
ypdm varchar2(12);
ph varchar2(60);
sccj varchar2(120);
yxq date;
pkg_unit_ratio number(16,10);
dqsl number(16,10);
ykcksl number(16,10);
ykmrdj number(16,10);
yklsdj number(16,10);
rksxh long;
ykrkxlh long;
ly_seq long;
ls_rkdh varchar2(12);
min_pkg_unit varchar2(12);
pkg_unit varchar2(12);
bz varchar2(1);
item_cnname varchar2(100);
item_cnalias varchar2(100);
itempkg_id varchar2(12);
pkg_name varchar2(40);
ykrkdh varchar2(12);
ldec_lsdj number(16,10);
newyklsdj number(16,10);
ldec_rklsdj number(16,10);
begin
    --取出入库明细的药品信息
    begin
      select rkdh,rksxh,ypdm,item_cnname,mrdj,lsdj,sccj,yxq,ph,ifzb,gmp,min_pkg_unit,pkg_unit_ratio,bz,dqsl,pkg_unit,ykcksl,ykmrdj,yklsdj,ykrkdh,ykrkxlh,ly_seq,item_cnalias,itempkg_id,pkg_name,rklsdj
      into ls_rkdh,rksxh,ypdm,item_cnname,mrdj,lsdj,sccj,yxq,ph,ifzb,gmp,min_pkg_unit,pkg_unit_ratio,bz,dqsl,pkg_unit,ykcksl,ykmrdj,yklsdj,ykrkdh,ykrkxlh,ly_seq,item_cnalias,itempkg_id,pkg_name,ldec_rklsdj
      from yfgl_t_rkmx where xlh=al_xlh;
       if (pkg_unit_ratio=0 or pkg_unit_ratio is null) then
         pkg_unit_ratio:=1;
       end if;
       if yklsdj is null then
          yklsdj :=lsdj * pkg_unit_ratio;
       end if;
       newyklsdj :=ad_xsj;
       --库存调价数量=库存数量,否则=调价数量
       dqsl := ad_sl ;
       if as_bz ='nt' then
          --lsdj :=round(yklsdj/pkg_unit_ratio,10);
          ldec_lsdj :=lsdj;
          lsdj :=ad_xsj;
          yklsdj :=lsdj * pkg_unit_ratio;
          newyklsdj :=ldec_lsdj * pkg_unit_ratio;
       end if;       if as_bz ='wt' then
          yklsdj :=lsdj * pkg_unit_ratio;
       end if;
       if as_bz ='wf' then
          lsdj :=ldec_rklsdj;
          yklsdj :=lsdj * pkg_unit_ratio;
       end if;       exception
       when others then
       os_retmsg := TO_CHAR(al_xlh) || '取yfgl_t_rkmx表失败! ~r~n' || SQLERRM;
       oi_return := -1;
       goto end_program;
    end;    --if as_bz='kc' or as_bz='wt' then
    if as_bz<>'nt' then
        ldec_lsdj := 0;
        ldec_lsdj := round(ad_xsj/pkg_unit_ratio,10);
    end if ;    --插调价明细yfgl_t_ypkctjmx
    begin
      /*
        外退反悔:
        旧药房零售单价:外退单的零售单价
        新药房零售单价;当前库存零售单价
        内退反悔:
        旧药房零售单价:当前库存零售单价
        新药房零售单价:内退单的零售单价
      */
      insert into yfgl_t_ypkctjmx (xlh,yfbm,tjdh,ypdm,rkdh,kcsl,mrdj,oldlsdj,newlsdj,oldyklsdj,newyklsdj,tjrq,rkxlh,sccj,czy,pkg_unit_ratio,rksxh,bz,min_pkg_unit,tjyy,item_cnalias,itempkg_id,pkg_name,pkg_unit,item_cnname)
       values (yfgl_yfseq.nextval,as_yfbm,as_tjdh,ypdm,ls_rkdh,dqsl,mrdj,lsdj,ldec_lsdj,yklsdj,newyklsdj,adt_now,al_xlh,sccj,as_czy,pkg_unit_ratio,rksxh,as_bz,min_pkg_unit,as_yy,item_cnalias,itempkg_id,pkg_name,pkg_unit,item_cnname);
       exception
       when others then
       os_retmsg := TO_CHAR(al_xlh)||'rkdh'|| ls_rkdh ||'yfbm'||as_yfbm|| '插yfgl_t_ypkctjmx表失败! ~r~n' || SQLERRM;
       oi_return := -1;
       goto end_program;
    end;
    --
    --更新yfgl_t_rkmx的价格as_bz='kc' 库存调价时才调
    begin
       if as_bz='kc' then
         update yfgl_t_rkmx set lsdj=ldec_lsdj where yfbm=as_yfbm and xlh=al_xlh;
       end if ;
       exception
       when others then
       os_retmsg := TO_CHAR(al_xlh)||'rkdh'|| ls_rkdh ||'yfbm'||as_yfbm|| '更新yfgl_t_rkmx表失败! ~r~n' || SQLERRM;
       oi_return := -1;
       goto end_program;    end;
    --
      oi_return := 1;
      os_retmsg := '';      <<end_program>>
      null;    exception
      when others then
        oi_return := SQLCODE;
        os_retmsg := SQLERRM;
        rollback;end yfgl_ypkctj;

解决方案 »

  1.   

     分段式的begin end 增加代码通读性!
      

  2.   

    还可以在不同BEGIN..END中添加不同EXCEPTION
      

  3.   

    那么写一个begin也行呢吗??
      

  4.   

    我也是第一次知道可以写多个begin 和end。
      

  5.   

    首先、“几个begin...end;语句”与“一个begin...end;语句”当然是不同的。使用多个begin...end;
          是有程序的要求而实现具体功能的。
    其次、要明白begin...end;的意义:在PL/SQL中BEGIN..END表示这是一个完整的块,begin   ...end;
         的意义可以理解为SQL语句执行的上下限,begin 是上限,SQL开始的地方,end是下限sql语句结束的
          地方.
    最后、明白begin...end;的功能:对包,函数,子程序等的定义至少需要一个begin...end;来开始和结束。
          如果程序中为了某些功能的具体需要可以添加子begin...end;块。比如可以在可疑的程序段使用子
          begin...end;这样可以保证这块可疑程序中如果有错误,而不至于影响该块外部其他程序的执行。
          比如楼主的实例代码中的这段子begin...end;:
          begin 
        --取出入库明细的药品信息 
        begin 
          select   rkdh,rksxh,ypdm,item_cnname,mrdj,lsdj,sccj,yxq,ph,ifzb,gmp,min_pkg_unit,pkg_unit_ratio,bz,dqsl,pkg_unit,ykcksl,ykmrdj,yklsdj,ykrkdh,ykrkxlh,ly_seq,item_cnalias,itempkg_id,pkg_name,rklsdj 
          into ls_rkdh,rksxh,ypdm,item_cnname,mrdj,lsdj,sccj,yxq,ph,ifzb,gmp,min_pkg_unit,pkg_unit_ratio,bz,dqsl,pkg_unit,ykcksl,ykmrdj,yklsdj,ykrkdh,ykrkxlh,ly_seq,item_cnalias,itempkg_id,pkg_name,ldec_rklsdj 
          from yfgl_t_rkmx where xlh=al_xlh; 
          …………………………
          exception 
          when others then 
          os_retmsg := TO_CHAR(al_xlh) || '取yfgl_t_rkmx表失败! ~r~n' || SQLERRM; 
          oi_return := -1; 
          goto end_program; 
        end; 
       如果表yfgl_t_rkmx里面不存在where xlh=al_xlh的数据,那么程序就会执行when others then里面的
           os_retmsg := TO_CHAR(al_xlh) || '取yfgl_t_rkmx表失败! ~r~n' || SQLERRM; 
          oi_return := -1; 
          goto end_program;
       然后跳到end_program,执行null,然后程序结束。但是如果这里没有子begin...end;程序就会跳到程序最后的那个exception when others then 里面的代码
            oi_return := SQLCODE; 
            os_retmsg := SQLERRM; 
            rollback; 
    这样很明显的就能看出有子begin...end;和没有,oi_return与os_retmsg的赋值就不同,有子begin...end;就能够很容易的知道程序是在哪里异常的。楼主程序中的select into 就是可疑程序,就是很容易抛出异常的代码。希望楼主能够明白。
      

  6.   


    赞一个begin...end可以看作是一个程序段落,这样代码可读性更强,而且可以在段里做针对性处理,而不作用与其他的段,或者全局。更便于逻辑的控制。
      

  7.   

    begin .....end 相当于SQL中的go....go。
    像批处理一样,一段一段的。
      

  8.   

    写一个beginend 和写多个当然有区别了,可能部门错误还需要继续往下执行,就分成多个beginend写了。