zoukankan      html  css  js  c++  java
  • 看来需要继续研究结算中心账户客商触发器了|OK||更新if else用法|

    itpub和csdn上面的求助原文:

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

    上图红色方框标示的是需要特别注意的,系统的要求必须“账户”和“客商辅助”必须一致,也就是这里的“账户”是北京公司,那么后面的“客商辅助”也必须选择北京公司,否则会出现账务和系统上的麻烦。
        备注:我们公司对同一个分公司,账户和客商是同一个编码,比如北京公司,账户和客商编码都是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。
    后来临时的解决办法是删除这个结算凭证,重新手工填写。

    基本的原因是知道的,在修改结算凭证的时候,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是判断数据存在的。
    感谢把触发器说透的作者,在今天他一个中午的陪伴下,完成了。

    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更新

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

    改用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; 
  • 相关阅读:
    【转】字典转模型需要注意的问题,以及第三方框架来处理字典转模型
    【转】使用SOAP访问Web服务
    Foundation框架2
    Foundation框架1
    什么是Protocol
    什么是Block
    什么么是Category
    ARC
    autorelease简介
    循环retain
  • 原文地址:https://www.cnblogs.com/sumsen/p/2524745.html
Copyright © 2011-2022 走看看