Oracle:在批量收集期间检测类型构造器中的异常

时间:2018-10-03 08:49:06

标签: oracle plsql bulk

环境:Oracle 11g 我有一个ty1类型,带有一些参数,例如s1,s2。

如果我这样使用它:

SELECT ty1(s1,s2) BULK COLLECT INTO l_collection_of_ty1 FROM ...

我收集了ty1。

现在,如果在ty1的构造函数调用之一中引发了异常,则我集合的相应元素设置为NULL,但是整个SELECT都起作用(没有异常,返回了集合)。

我的问题是,是否可以在SELECT之后立即检测到这一点而不必遍历集合?也许甚至可以像SQL%BULK_EXCEPTION对DML一样访问原始错误消息吗?

我想到的一种解决方法是在BULK COLLECT期间不使用构造函数,而是读取s1和s2的集合,然后在我可以处理异常的自己的循环中构造TYPE,但这是更多的代码,我会如果Oracle有某种构建方式,请选择它。

3 个答案:

答案 0 :(得分:1)

这是一个测试用例,演示了通过批量选择引发了所有异常,但是删除了NO_DATA_FOUND。

-- remember to retreive dbms_output
SET SERVEROUTPUT ON

CREATE OR REPLACE FUNCTION p1 (v1 PLS_INTEGER)
   RETURN NUMBER
AS
BEGIN
   CASE v1
      WHEN 1
      THEN
         RAISE ACCESS_INTO_NULL;
      WHEN 2
      THEN
         RAISE CASE_NOT_FOUND;
      WHEN 3
      THEN
         RAISE COLLECTION_IS_NULL;
      WHEN 4
      THEN
         RAISE CURSOR_ALREADY_OPEN;
      WHEN 5
      THEN
         RAISE DUP_VAL_ON_INDEX;
      WHEN 6
      THEN
         RAISE INVALID_CURSOR;
      WHEN 7
      THEN
         RAISE INVALID_NUMBER;
      WHEN 8
      THEN
         RAISE LOGIN_DENIED;
      WHEN 9
      THEN
         RAISE NO_DATA_FOUND;
      WHEN 10
      THEN
         RAISE NOT_LOGGED_ON;
      WHEN 11
      THEN
         RAISE PROGRAM_ERROR;
      WHEN 12
      THEN
         RAISE ROWTYPE_MISMATCH;
      WHEN 13
      THEN
         RAISE SELF_IS_NULL;
      WHEN 14
      THEN
         RAISE STORAGE_ERROR;
      WHEN 15
      THEN
         RAISE SUBSCRIPT_BEYOND_COUNT;
      WHEN 16
      THEN
         RAISE SUBSCRIPT_OUTSIDE_LIMIT;
      WHEN 17
      THEN
         RAISE SYS_INVALID_ROWID;
      WHEN 18
      THEN
         RAISE TIMEOUT_ON_RESOURCE;
      WHEN 19
      THEN
         RAISE TOO_MANY_ROWS;
      WHEN 20
      THEN
         RAISE VALUE_ERROR;
      WHEN 21
      THEN
         RAISE ZERO_DIVIDE;
      ELSE
         RETURN v1;
   END CASE;
END;
/

DECLARE
   TYPE type1 IS TABLE OF NUMBER;

   col1   type1;
BEGIN
   FOR ii IN 1 .. 22
   LOOP
      BEGIN
         SELECT p1 (ii)
           BULK COLLECT INTO col1
           FROM DUAL;

         IF col1 (1) IS NULL
         THEN
            DBMS_OUTPUT.put_line (TO_CHAR (ii, '00') || ': NULL');
         ELSE
            DBMS_OUTPUT.put_line (TO_CHAR (ii, '00') || ': ' || col1 (1));
         END IF;
      EXCEPTION
         WHEN OTHERS
         THEN
            DBMS_OUTPUT.put_line (
                  TO_CHAR (ii, '00')
               || ': exception '
               || SQLCODE);
      END;
   END LOOP;
END;
/

答案 1 :(得分:0)

我为您编写了一个小测试用例,该异常必须在ty1内吞下且不能引发,因为否则选择将无法成功完成:

create or replace function p1 (v1 number) return number
as
begin
if v1 = 1 then
return 1;
elsif v1 = 2 then
raise_application_error(-20010,'err 2');
else
raise_application_error(-20010,'err 3');
end if;
end;
/

declare
type type1 is table of number;
col1 type1;
begin
select p1(level) bulk collect into col1 from dual connect by level <=3;
end;
/

结果:

Error report -
ORA-20010: err 2

因此,我对您的建议是-如果您想靠近解决方案-在ty1中处理异常的地方,请将异常写入表中。然后,您可以访问此表以查找异常,而无需遍历整个集合。但老实说,在集合中循环PL / SQL有什么问题,它们全都在内存中? HTH

答案 2 :(得分:0)

我只有两个选择。

  1. 构造函数内部消耗了一个异常。
  2. 正在使用另一个构造函数。

示例:

create or replace type ty1 as object (p1 number
, constructor function  ty1 (p1 varchar2) 
    return self as result);

create or replace type body ty1 
is 
  constructor function ty1 (p1 varchar2) 
    return self as result is
    x number;
  begin
   raise_application_error(-20000,'Always Exception');
   return;
  end;
end;

测试1也不例外:

declare
 type l_collection_of_ty1 is table of ty1;
 a varchar2(4000);
 x   l_collection_of_ty1;
begin 

--test1   select ty1(level) bulk collect into x from dual connect by level < 10;
     -- no exceptions 
 --test2  select ty1(level||1) bulk collect into x from dual connect by level < 10; 
       -- exceptions

  --test3 select ty1(null) bulk collect into x from dual connect by level < 10; 
       -- exceptions
end; 

在Test1中,db使用属性值构造函数。默认情况下会生成。
在Test2中,db使用的是用户定义的构造函数。
在Test3中,db无法找出应该使用哪个构造函数。()