看来需要继续研究结算中心账户客商触发器了|OK||更新if else用法|

itpub和csdn上面的求助原文:

oracle数据库是用在我们公司用友NC财务软件上,NC版本是5.02。
我是公司的NC的系统管理员。
我们使用了资金管理系统,需要使用一个功能是填制结算凭证,如下图:

看来需要继续研究结算中心账户客商触发器了|OK||更新if else用法|

上图红色方框标示的是需要特别注意的,系统的要求必须“账户”和“客商辅助”必须一致,也就是这里的“账户”是北京公司,那么后面的“客商辅助”也必须选择北京公司,否则会出现账务和系统上的麻烦。
    备注:我们公司对同一个分公司,账户和客商是同一个编码,比如北京公司,账户和客商编码都是010201,上海公司都是010301.
     
    我经过查看后台数据库,在填制结算凭证的时候,影响到的是两个表,分包是结算分录fts_voucher_b,结算凭证fts_voucher,这两个表通过字段pk_voucher关联。
    上图中的“账户”和“客商辅助”是存在fts_voucher_b中,但是不是直接的代码,比如010201,而是两个pk代码值。
   经过几天的研究,我打算通过触发器完成这个账户和客商一致的问题,可是上面也说到,在填制结算凭证,后台存入fts_voucher_b中的是pk值,必须要凭证保存到数据库之后才能查询到不一致的情况。
   查询结算分录账户和客商不一致的情况,我sql如下:

select



       bd_accid.accidcode,



       gl_freevalue.valuecode



  from fts_voucher_b, bd_accsubj, gl_freevalue, bd_accid



where fts_voucher_b.pk_subject = bd_accsubj.pk_accsubj



   and fts_voucher_b.pk_ass = gl_freevalue.freevalueid



   and fts_voucher_b.dr = '0'



   and fts_voucher_b.pk_corp = '1162'



   and fts_voucher_b.pk_account = bd_accid.pk_accid



   and length(gl_freevalue.valuecode) = '6'



   and substr(gl_freevalue.valuecode, 0, 1) = '0'



   and bd_accid.accidcode != gl_freevalue.valuecode

 

复制代码
    这里为了将账户和客商的pk值转化为数字代码(上面备注说到的北京公司010201),通过了4个表的关联查询。
   之后触发器把上面的代码作为了游标,触发器如下:
 

create or replace trigger CHECK_VOUCHER



before insert or update on fts_voucher  



  for each row



declare



  -- local variables here



  pk_bas char(20);



  accode char(6);



  vcode char(6);



cursor basjob(id char) is



    select fts_voucher_b.pk_voucher,bd_accid.accidcode, gl_freevalue.valuecode



      from fts_voucher_b,bd_accid, gl_freevalue



     where fts_voucher_b.pk_voucher = id



       and     fts_voucher_b.pk_ass = gl_freevalue.freevalueid



               and fts_voucher_b.pk_account = bd_accid.pk_accid



               and length(gl_freevalue.valuecode) = '6'



               and substr(gl_freevalue.valuecode, 0, 1) = '0';



begin



  open basjob(:new.pk_voucher);



  loop



fetch basjob



      into pk_bas, accode , vcode;



    exit when basjob%notfound;



    --raise_application_error(-20001,pk_accidcode||'hhh');



  end loop;



  close basjob;



  if pk_bas is not null then



    if accode<>vcode then



begin



raise_application_error(-20001,'结算凭证号'||:new.cent_typeid||'账户和客商不一致,请修改!');



    end;



  end if;



  end if;



end CHECK_VOUCHER;

 

   

 

复制代码

     解释:触发器是写在了表结算凭证fts_voucher上而不是写在结算分录fts_voucher_b上,因为上面提到凭证没有保存的时候是不会相应游标里面的sql。 这里借用了fts_voucher和fts_voucher_b共同有一个同样的值pk_voucher。触发器是在审核结算凭证的时候引起触发(审核的时候fts_voucher会有新值传入)
    目前,这个触发器已经完成了如果填制的结算凭证账户和客商不一致引起触发报错不给审核额通过。
   但是很快发现了问题,就是审核发现错误之后,让制单人回到填制结算凭证那里修改账户和客商保存一致,保存的时候同意会报错,不能保存。
   基本的原因是知道的,在修改结算凭证的时候,pk_voucher并没有变动,错误的结算凭证还在fts_voucher_b里面,系统在保存之前和过程中还是识别的这个没有改的错误的结算凭证,因此即使修改了也是不让保存。
   目前我只要让同事删除这个结算凭证,重新制单。
   
   有几点疑问:
   1,这个问题还有解决的可能性吗?就是触发器在触发报错之后,制单人可以直接原有基础上修改而不用删除重新制单。
   2,可否使用after触发器,让在保存之后报错,这时候触发器直接写在fts_voucher_b上?
   3,是不是我的触发器写的不够好,还有其他的优化?
   如果方便,可以加我qq344529501,谢谢!
   
下面是搞定的sql,感谢一位高手

create or replace trigger fts_v_b



  before insert or update on   fts_voucher_b



  for each row



declare



  -- local variables here



  accode char(6);



  vcode char(6);



  vRowsCount number;



begin



select nvl(count(*),0) into vRowsCount from fts_voucher_b, gl_freevalue, bd_accid



             where  gl_freevalue.freevalueid=:new.pk_ass



               and  bd_accid.pk_accid=:new.pk_account



               and length(gl_freevalue.valuecode) = '6'



               and substr(gl_freevalue.valuecode, 0, 1) = '0';



if vRowsCount > 0 then



   select distinct bd_accid.accidcode,  gl_freevalue.valuecode into accode,vcode



   from fts_voucher_b, gl_freevalue, bd_accid



             where  gl_freevalue.freevalueid=:new.pk_ass



               and  bd_accid.pk_accid=:new.pk_account



               and length(gl_freevalue.valuecode) = '6'



               and substr(gl_freevalue.valuecode, 0, 1) = '0';  



else



    return;



end if;



if  accode<>vcode   then



       raise_application_error(-20001,'结算凭证账户'||accode||'和客商'||vcode|| '不一致!');



end if;  



end  fts_v_b;

 

复制代码

本以为触发器已经完美。

create or replace trigger CHECK_VOUCHER



  before insert or update on fts_voucher  



  for each row



declare



  -- local variables here



  pk_bas char(20);



 



  cursor basjob(id char) is



    select pk_voucher



      from fts_voucher_b



     where pk_voucher = id



       and pk_voucher in



           (select fts_voucher_b.pk_voucher



              from fts_voucher_b, gl_freevalue, bd_accid



             where fts_voucher_b.pk_ass = gl_freevalue.freevalueid



               and fts_voucher_b.pk_account = bd_accid.pk_accid



               and length(gl_freevalue.valuecode) = '6'



               and substr(gl_freevalue.valuecode, 0, 1) = '0'



               and bd_accid.accidcode <> gl_freevalue.valuecode);



 



begin



  open basjob(:new.pk_voucher);



  loop



  



    fetch basjob



      into pk_bas;



    exit when basjob%notfound;



    --raise_application_error(-20001,pk_accidcode||'hhh');



  end loop;



  close basjob;



 



  if pk_bas is not null then



    begin



      raise_application_error(-20001,



                              '结算凭证'|| :new.cent_typeid ||'账户和客商不一致,请删除,之后重新填写结算凭证!');



    end;



  end if;



end CHECK_VOUCHER;

 

可是今天孙娜填写了一个错误的结算凭证,就是账户和客商不一致,审核的时候报错。
但是孙娜在结算凭证那里改正这个错误的凭证,之后报错却同样的触发了这个trigger。
后来临时的解决办法是删除这个结算凭证,重新手工填写。

看来需要继续研究结算中心账户客商触发器了|OK||更新if else用法|

基本的原因是知道的,在修改结算凭证的时候,pk_voucher并没有变动,因为之前的结算凭证还在fts_voucher_b里面,系统在保存之前和过程中还是识别的这个没有改的错误的结算凭证,因此即使修改了也是不让保存。
怎么解决呢
但是奇怪啊,我明明写的是before insert or update on fts_voucher  ,修改结算凭证是针对fts_voucher_b的,为什么这里会触发呢

4.1 23:13更新:after触发器试一下
4.3 1:34 update:

create or replace trigger CHECK_VOUCHER

 before insert or update on fts_voucher



  for each row

declare



  -- local variables here



  pk_bas char(20);



  accode char(6);

  vcode char(6);



  cursor basjob(id char) is

    select fts_voucher_b.pk_voucher,bd_accid.accidcode, gl_freevalue.valuecode

      from fts_voucher_b,bd_accid, gl_freevalue

     where fts_voucher_b.pk_voucher = id



       and     fts_voucher_b.pk_ass = gl_freevalue.freevalueid

               and fts_voucher_b.pk_account = bd_accid.pk_accid

               and length(gl_freevalue.valuecode) = '6'

               and substr(gl_freevalue.valuecode, 0, 1) = '0';    



 begin

  open basjob(:new.pk_voucher);

  loop

    fetch basjob

      into pk_bas, accode , vcode;



    exit when basjob%notfound;



    --raise_application_error(-20001,pk_accidcode||'hhh');

   end loop;

  close basjob; 



  if pk_bas is not null then



    if accode<>vcode then



    begin



      raise_application_error(-20001,:new.pk_voucher||:old.pk_voucher||'结算凭证号:'||:new.cent_typeid||'的账户'||accode||



      '和客商辅助'||vcode||'不一致,请修改!');



  update fts_voucher set pk_voucher='1162N51000000001'||substr(:new.pk_voucher,17,4)



  where pk_voucher=:old.pk_voucher;



  update fts_voucher_b set pk_voucher='1162N51000000001'||substr(:new.pk_voucher,17,4)



  where pk_voucher=:old.pk_voucher;



    end;

  end if;



  end if;

end CHECK_VOUCHER;

 


4.6 0:34 更新 ,明天继续问一路

create or replace trigger fts_v_b



  before insert OR update on   fts_voucher_b



  for each row



 



begin



 select bd_accid.accidcode,  gl_freevalue.valuecode from fts_voucher_b, gl_freevalue, bd_accid



             where :new.pk_ass = gl_freevalue.freevalueid



               and :new.pk_account= bd_accid.pk_accid



               and length(gl_freevalue.valuecode) = '6'



               and substr(gl_freevalue.valuecode, 0, 1) = '0'



  if bd_accid.accidcode<>gl_freevalue.valuecode



   then aise_application_error(-20001,



                              '结算凭证'||'账户和客商不一致,请删除,之后重新填写结算凭证!');



  end;



  end if;



 



end fts_v_b;

 

 

更新4.6 13:38

create or replace trigger fts_v_b

  before insert or update on   fts_voucher_b

  for each row 

declare

  -- local variables here

    pk_bas char(20);

 

begin

 select distinct :new.pk_voucher into pk_bas

 from fts_voucher_b, gl_freevalue, bd_accid

             where  gl_freevalue.freevalueid=:new.pk_ass

               and  bd_accid.pk_accid=:new.pk_account

               and length(gl_freevalue.valuecode) = '6'

               and substr(gl_freevalue.valuecode, 0, 1) = '0'

               and bd_accid.accidcode != gl_freevalue.valuecode;   

  if  pk_bas is not null  then 

       raise_application_error(-20001,'结算凭证账户和客商不一致!');

  

  

   

 end if;  

 end  fts_v_b;

 

 

第二种:

create or replace trigger fts_v_b

  before insert or update on   fts_voucher_b

  for each row 

declare

  -- local variables here

    accode char(6);

  vcode char(6);

begin

 select distinct bd_accid.accidcode,  gl_freevalue.valuecode into accode,vcode 

 from fts_voucher_b, gl_freevalue, bd_accid

             where  gl_freevalue.freevalueid=:new.pk_ass

               and  bd_accid.pk_accid=:new.pk_account

               and length(gl_freevalue.valuecode)='6'

               and substr(gl_freevalue.valuecode,0,1)='0';   

  if nvl(accode,'')<>nvl(vcode,'')   then 

       raise_application_error(-20001,'结算凭证账户'||accode||'和客商'||vcode|| '不一致!');

 end if;  



 end  fts_v_b;

 

2012.4.6 14:15更新:

create or replace trigger fts_v_b

  before insert or update on   fts_voucher_b

  for each row 

declare

  -- local variables here

  accode char(6);

  vcode char(6);

  vRowsCount number;

begin

 select nvl(count(*),0) into vRowsCount from fts_voucher_b, gl_freevalue, bd_accid

             where  gl_freevalue.freevalueid=:new.pk_ass

               and  bd_accid.pk_accid=:new.pk_account

               and length(gl_freevalue.valuecode) = '6'

               and substr(gl_freevalue.valuecode, 0, 1) = '0';

 

 if vRowsCount > 0 then

   select distinct bd_accid.accidcode,  gl_freevalue.valuecode into accode,vcode 

   from fts_voucher_b, gl_freevalue, bd_accid

             where  gl_freevalue.freevalueid=:new.pk_ass

               and  bd_accid.pk_accid=:new.pk_account

               and length(gl_freevalue.valuecode) = '6'

               and substr(gl_freevalue.valuecode, 0, 1) = '0';  

 else

    return;

 end if;

 

 if  accode<>vcode   then 

       raise_application_error(-20001,'次结算凭证账户'||accode||'和客商'||vcode|| '不一致,请修改!');

  

 end if;  

 end  fts_v_b;

 


上面的vRowsCount > 0是判断数据存在的。
感谢把触发器说透的作者,在今天他一个中午的陪伴下,完成了。

看来需要继续研究结算中心账户客商触发器了|OK||更新if else用法|

4.6 18:28更新,这样也行。在accode<>vocde之前先增加 if accode=vcode (实测前后没有影响)

 1 create or replace trigger FTS2

 2   before insert or update on   fts_voucher_b

 3   for each row

 4 declare

 5   -- local variables here

 6     accode char(6);

 7   vcode char(6);

 8 begin

 9   

10  select distinct bd_accid.accidcode,  gl_freevalue.valuecode into accode,vcode

11  from fts_voucher_b, gl_freevalue, bd_accid

12              where  gl_freevalue.freevalueid=:new.pk_ass

13                and  bd_accid.pk_accid=:new.pk_account

14                and length(gl_freevalue.valuecode)='6'

15                and substr(gl_freevalue.valuecode,0,1)='0';   

16                

17   if accode=vcode then   

18        RETURN;

19        END IF;        

20                

21   if accode<>vcode then

22        raise_application_error(-20001,'此结算凭证账户:'||accode||'和客商辅助:'||vcode|| '不一致,请修改!');

23  end if;  

24 

25  end FTS2;

 

18:43 更新,使用 else if

create or replace trigger FTS2
  before insert or update on   fts_voucher_b
  for each row
declare
  -- local variables here
    accode char(6);
  vcode char(6);
begin
  
 select distinct bd_accid.accidcode,  gl_freevalue.valuecode into accode,vcode
 from fts_voucher_b, gl_freevalue, bd_accid
             where  gl_freevalue.freevalueid=:new.pk_ass
               and  bd_accid.pk_accid=:new.pk_account
               and length(gl_freevalue.valuecode)='6'
               and substr(gl_freevalue.valuecode,0,1)='0';   
               
 if accode=vcode then   
       RETURN;           
               
 else if accode<>vcode then
       raise_application_error(-20001,'此结算凭证账户:'||accode||'和客商辅助:'||vcode|| '不一致,请修改!');
 end if;  
 end if;

 end FTS2;

4.9 9:09更新

刚刚杨洋做了一笔资金下拨,两家的,结果保存的时候报错。

看来需要继续研究结算中心账户客商触发器了|OK||更新if else用法|

改用eric hu的触发器之后解决。

今天有时间研究两个客商为什么不行

4.9 14:23更新:中午测试了一下,发现不使用count*数量变量的触发器下面,如果结算凭证分录里面都是涉及到1003,也就是有客商和账户的,没有问题,但是只要有一行是其他科目,没有账户和客商辅助,就不能保存,触发器提示没有数据。

更新了一下eric hu的sql,更容易看懂(可以看出accode<>vcode受到前面 vRowsCount > 0的影响,否则accode和vcode就没有传值)

 

 1 create or replace trigger fts_v_b

 2   before insert or update on   fts_voucher_b

 3   for each row 

 4 declare

 5   -- local variables here

 6   accode char(6);

 7   vcode char(6);

 8   vRowsCount number;

 9 begin

10  select nvl(count(*),0) into vRowsCount from fts_voucher_b, gl_freevalue, bd_accid

11              where  gl_freevalue.freevalueid=:new.pk_ass

12                and  bd_accid.pk_accid=:new.pk_account

13                and length(gl_freevalue.valuecode) = '6'

14                and substr(gl_freevalue.valuecode, 0, 1) = '0';

15  

16  if vRowsCount > 0 then

17    select distinct bd_accid.accidcode,  gl_freevalue.valuecode into accode,vcode 

18    from fts_voucher_b, gl_freevalue, bd_accid

19              where  gl_freevalue.freevalueid=:new.pk_ass

20                and  bd_accid.pk_accid=:new.pk_account

21                and length(gl_freevalue.valuecode) = '6'

22                and substr(gl_freevalue.valuecode, 0, 1) = '0';  

23                

24          if  accode<>vcode   then 

25     raise_application_error(-20001,'此结算凭证账户:'||accode||'和客商辅助:'||vcode|| '不一致,请修改!');

26   

27  end if;  

28  else

29     return;

30  end if;

31  end  fts_v_b;

 

 2012.4.13 14:42 更新exception用法,这样可以不用那个数量变量了(exception必须要放在最后)

create or replace trigger FTS2

  before insert or update on   fts_voucher_b

  for each row

declare

  -- local variables here

  accode char(6);

  vcode  char(6);

begin



  select distinct bd_accid.accidcode, gl_freevalue.valuecode

    into accode, vcode

    from fts_voucher_b, gl_freevalue, bd_accid

   where gl_freevalue.freevalueid = :new.pk_ass

     and bd_accid.pk_accid = :new.pk_account

     and length(gl_freevalue.valuecode) = '6'

     and substr(gl_freevalue.valuecode, 0, 1) = '0';



  

  if accode = vcode then

    return;

  end if;

  if accode <> vcode then raise_application_error(-20001,'次结算凭证账户'||accode||'和客商'||vcode|| '不一致,请修改!');

  end if;



 exception

  when no_data_found then  

    return;

end FTS2;

 2012.6.21更新

下面是if else的用法,简化了一些sql

 1 create or replace trigger FTS2

 2   before insert or update on   fts_voucher_b

 3   for each row

 4 declare

 5   -- local variables here

 6   accode char(6);

 7   vcode  char(6);

 8 begin

 9 

10   select distinct bd_accid.accidcode, gl_freevalue.valuecode

11     into accode, vcode

12     from fts_voucher_b, gl_freevalue, bd_accid

13    where gl_freevalue.freevalueid = :new.pk_ass

14      and bd_accid.pk_accid = :new.pk_account

15      and length(gl_freevalue.valuecode) = '6'

16      and substr(gl_freevalue.valuecode, 0, 1) = '0';

17 

18   

19   if accode = vcode then

20     return;

21  else

22     raise_application_error(-20001,'次结算凭证账户'||accode||'和客商'||vcode|| '不一致,请修改!');

23   end if;

24 

25  exception

26   when no_data_found then  

27     return;

28 end FTS2;

 

 



更新4.14 22:50,看看一周前略显幼稚的写法,不过思路已经成型:

 1 create or replace trigger fts_v_b

 2 

 3   before insert OR update on   fts_voucher_b

 4 

 5   for each row

 6 

 7  

 8 

 9 begin

10 

11  select bd_accid.accidcode,  gl_freevalue.valuecode from fts_voucher_b, gl_freevalue, bd_accid

12 

13              where :new.pk_ass = gl_freevalue.freevalueid

14 

15                and :new.pk_account= bd_accid.pk_accid

16 

17                and length(gl_freevalue.valuecode) = '6'

18 

19                and substr(gl_freevalue.valuecode, 0, 1) = '0'

20 

21   if bd_accid.accidcode<>gl_freevalue.valuecode

22 

23    then aise_application_error(-20001,

24 

25                               '结算凭证'||'账户和客商不一致,请删除,之后重新填写结算凭证!');

26 

27   end;

28 

29   end if;

30 

31 end fts_v_b; 

你可能感兴趣的:(if else)