将函数分配给变量并在过程中使用它

Assign function to a variable and use it within procedure

我在过程中使用 'Next Sequence Values' 时遇到问题。

我有 'external' 函数来 return 序列的下一个值。 在我的程序中,我想将该序列的值分配给一个变量 并在我的光标中使用该变量(因为我在我的光标中使用联合语句)。

但它不起作用。

    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: error number argument to raise_application_error of 1 is out of range"

请帮助我。谢谢。

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

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

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 pragma 中的日志程序。这样日志记录就不会干扰更广泛的事务。 Find out more.

我已经发布了答案。它可以进一步改进。 pragma exception_init 用于捕获错误(在我的例子中 - 完整性约束)。

我删除了调用 'next sequence value' 的函数,因为它可以在执行插入之前直接调用。

@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;