环境: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有某种构建方式,请选择它。
答案 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)
我只有两个选择。
示例:
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无法找出应该使用哪个构造函数。()