将函数赋值给变量并在过程中使用它

时间:2015-03-24 06:09:43

标签: sql oracle stored-procedures plsql

我在程序中使用“下一个序列值”时出现问题。

我有'external'函数来返回Sequence的Next Value。 在我的程序中,我想将该序列的值分配给变量 并在我的游标中使用该变量(因为我在游标中使用了union语句)。

但它没有用。

    CREATE OR REPLACE Procedure HR.insert_TBL_APP is

    --declare variables for insert
    v_TA_SNO VARCHAR2(10);
    v_TA_SEQNO VARCHAR2(6);
    v_TA_DESC VARCHAR2(10);

    --declare variable to store the sequence number
    var_TaSeqno varchar2(6);

    -- Validation
    v_check   VARCHAR2 (10 Byte);

    err_code varchar2(50);
    err_msg varchar2(100);

    v_table_name varchar2(50):='TBL_APP';

    error_found exception;


    cursor c1 is
    select distinct TA_SNO,
                 TA_SEQNO,
                  TA_DESC
                  from (                                                                     
    SELECT hdr.FIRST_NO TA_SNO,
        var_TaSeqno TA_SEQNO, -- using variable to assign the sequence no
        hdr.descrip TA_DESC     
    FROM
        FORMS_HDR hdr
    WHERE     
        hdr.seco_name = 'TST121'
    union
    SELECT hdr.FIRST_NO TA_SNO,
        var_TaSeqno TA_SEQNO, -- using variable to assign the sequence no
        hdr.descrip TA_DESC     
    FROM
        FORMS_HDR hdr
    WHERE     
        hdr.seco_name = 'TST122');


    begin

    if c1%isopen then

    close c1;
    end if;

    v_check:=null;

    FOR i IN c1 LOOP

    --assign variables for insert
    v_TA_SNO  := i.TA_SNO;
    v_TA_SEQNO  := i.TA_SEQNO;
    v_TA_DESC  := i.TA_DESC;

    begin

    -- calling the Function taSeqNoFunc and assign the 
    --sequence No into the variable var_TaSeqno
     var_TaSeqno := HR.taSeqNoFunc();
     select TA_SNO
      into v_check
      from TBL_APP  a
     where  TA_SNO = i.TA_SNO
      and TA_SEQNO =i.TA_SEQNO;

     exception
      when no_data_found then

      --insert into target table
      INSERT INTO TBL_APP (TA_SNO,
                           TA_SEQNO,
                           TA_DESC
                            )  
                            values  (v_TA_SNO,
                            v_TA_SEQNO,
                            v_TA_DESC
                            );

        when others then
         raise error_found;
       end ;

      end loop;


      exception when error_found then

       rollback;        
      err_code := SQLCODE;
      err_msg := SUBSTR(SQLERRM, 1, 200);      
      insert into TA_ERROR_LOG values (v_check,v_table_name,'An error 
      was  encountered '||err_code||':'||err_msg,sysdate);
      commit;

     raise_application_error(err_code,err_msg);

     end;
     /

错误最终会在结尾附近进入raise_application_error:

“ORA-21000:raise_application_error为1的错误编号参数超出范围”

请帮帮我。谢谢。

3 个答案:

答案 0 :(得分:3)

raise_application_error()过程是内置的Oracle PL / SQL。它提供了我们可以将自定义消息与用户定义的异常相关联的内容。用户定义的异常必须具有-20999到-20000范围内的数字。 Find out more

由于内部EXCEPTION块中的代码,您收到此错误:

    when others then
     raise error_found;

您正在引发用户定义的异常,但是您没有使用EXCEPTION_INIT pragma与错误号相关联。 Find out more。因此,Oracle默认为SQLCODE = 1SQLERRM = 'User-Defined Exception'

显然1超出raise_application_error()的允许范围。因此,当你来到外部EXCEPTION块时会出现错误。

避免这种情况的方法是删除ERROR_FOUND异常并依赖Oracle的默认异常处理。

在最里面的块中,您想要重新引发除NO_DATA_FOUND之外的任何异常。最简单的方法是删除WHEN OTHERS子句。然后,在外部块中,您将获得可以记录的SQLCODE和SQLERRM的有意义值。然后只需使用RAISE将它们传播到堆栈中....

exception 

    when others then

       rollback;        
      err_code := SQLCODE;
      err_msg := SUBSTR(SQLERRM, 1, 200);      
      insert into TA_ERROR_LOG values (v_check,v_table_name,'An error 
      was  encountered '||err_code||':'||err_msg,sysdate);
      commit;

     raise;

end; 

您不仅不会从raise_application_error()收到错误,您的日志将包含有用的错误编号和消息。


顺便说一句,在EXCEPTION块中使用ROLLBACK和COMMIT是不好的做法。更好的方法是编写一个由AUTONOMOUS_TRANSACTION编译指示覆盖的日志记录过程。这样,日志记录不会干扰更广泛的事务。 Find out more

答案 1 :(得分:1)

传递给raise_application_error过程的错误号必须是-20000 ..- 20999范围内的负整数。

对于用户定义的异常,SQLCODE始终返回+1,因此您将+1作为传递 raise_application_error程序的错误编号,超出范围。

答案 2 :(得分:0)

我已经发布了答案。它可以进一步改进。 pragma exception_init 用于捕获错误(在我的情况下 - Integrity Constraint)。

我已删除了调用'下一个序列值'因为它可以在执行插入之前直接调用。

@APC谢谢:)

CREATE OR REPLACE Procedure HR.insert_TBL_APP is

--declare variables for insert
v_TA_SNO VARCHAR2(10);
v_TA_SEQNO VARCHAR2(6);
v_TA_DESC VARCHAR2(10);

-- Validation
v_check   VARCHAR2 (10 Byte);

err_code varchar2(50);
err_msg varchar2(200);

v_table_name varchar2(50):='TBL_APP';

error_found exception;
parent_not_found exception;   --  use it to catch the Integrity Constraint
pragma exception_init(parent_not_found, -2291);

cursor c1 is
select distinct TA_SNO,
                TA_SEQNO,
                TA_DESC
from (                                                                     
      SELECT hdr.FIRST_NO TA_SNO,
        -1 TA_SEQNO, -- assign a dummy value as sequence no
         hdr.descrip TA_DESC     
      FROM
         FORMS_HDR hdr
      WHERE     
         hdr.seco_name = 'TST121'
  union
      SELECT hdr.FIRST_NO TA_SNO,
         -2 TA_SEQNO, -- assign a dummy value as sequence no
         hdr.descrip TA_DESC     
      FROM
         FORMS_HDR hdr
      WHERE     
         hdr.seco_name = 'TST122');


begin

if c1%isopen then
   close c1;
end if;

v_check:=null;

FOR i IN c1 LOOP

--assign variables for insert
v_TA_SNO  := i.TA_SNO;
v_TA_SEQNO  := i.TA_SEQNO;
v_TA_DESC  := i.TA_DESC;

begin

 --var_TaSeqno := HR.taSeqNoFunc();  --the variable will not be used
 select TA_SNO
  into v_check
  from TBL_APP  a
 where  TA_SNO = i.TA_SNO
  and TA_SEQNO =i.TA_SEQNO;

 exception
  when no_data_found then

  Begin  -- added line to use exception

  --insert into target table
  INSERT INTO TBL_APP (TA_SNO,
                       TA_SEQNO,
                       TA_DESC
                        )  
                        values  (v_TA_SNO,
                       TA_SEQNO.nextval, --insert the nextval directly
                        v_TA_DESC
                        );

       --when the integrity constraint (parent key) error is thrown, insert into the TA_ERROR_LOG
         exception
            when parent_not_found then  
            rollback;        
            err_msg := SUBSTR(SQLERRM, 1, 200);      
            insert into TA_ERROR_LOG values (v_check,v_table_name, err_msg, sysdate);
         commit;

  end;   -- end begin for using the exception

    when others then
     raise error_found;
   end ;

  end loop;


  exception when error_found then

  rollback;        
   err_code := SQLCODE;
   err_msg := SUBSTR(SQLERRM, 1, 200);      
   insert into TA_ERROR_LOG values (v_check,v_table_name, err_msg, sysdate);
  commit;

 raise_application_error(err_code,err_msg);

 end;