Oracle-For循环输出问题

时间:2018-12-06 09:57:05

标签: oracle plsql

我在oracle中有此函数,应该以逗号分隔的数字列表作为输入,并迭代每个数字,然后将其传递给另一个函数,然后通过管道输出。

create or replace FUNCTION FUNC1(num_list varchar2,separator varchar2) RETURN typeAs PIPELINED 
as 
begin
FOR nums in (select regexp_substr(num_list,'[^'||separator||']+', 1, level) num from dual
  connect by regexp_substr(num_list, '[^'||separator||']+', 1, level) is not null)
loop
PIPE ROW(typeA(NVL(nums.num,0) ,NVL(FUNC2(nums.num),0)));
end loop;
end;

注意:

create or replace TYPE typeA AS OBJECT (num varchar2(20),val varchar2(20))
create or replace TYPE typeAs AS TABLE OF typeA;

如果传递给FUNC2时列表中的所有数字将返回非null的输出,则该函数正常工作。但是,如果一个数字在传递给FUNC2时返回null,则列表中的所有后续数字都不会显示在FUNC1的输出中。

编辑:结果:

select * from table(FUNC1('1111,4333,121212',',')) :
output:
-----------------
1111 | val1

其他两个数字未显示在输出中,因为FUNC2('4333')为null,因为知道FUNC2('121212')具有值。 :

select * from table(FUNC1('1111,2222,121212',',')) :
output:
-----------------
1111     | val1
2222     | val2
121212   | val3

1 个答案:

答案 0 :(得分:2)

对于输入值4333,如果REST_FRAMEWORK = { ... 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAdminUser', ), ... } 抛出func2异常而不是返回null,您将看到这种效果。如果该函数正在从另一个表中查找值,则可能有意义

因为您对no_data_found的调用是在SQL上下文中进行的,因此异常是致命的,并且在遇到异常时执行将失败,而无需任何预兆。如果从PL / SQL上下文调用func1,则会看到异常。

作为具有虚拟func1的演示:

func2

和您的原始功能:

create or replace function func2(p_num number) return varchar2 as
begin
  if p_num = 4333 then
    raise no_data_found;
  end if;

  return case p_num
    when 1111 then 'val1'
    when 2222 then 'val2'
    when 121212 then 'val3'
    else null
  end;
end func2;
/

您可以更改create or replace FUNCTION FUNC1(num_list varchar2,separator varchar2) RETURN typeAs PIPELINED as l_val varchar2(20); begin FOR nums in (select regexp_substr(num_list,'[^'||separator||']+', 1, level) num from dual connect by regexp_substr(num_list, '[^'||separator||']+', 1, level) is not null) loop PIPE ROW(typeA(NVL(nums.num,0) ,NVL(FUNC2(nums.num),0))); end loop; end; / select * from table(FUNC1('1111,4333,121212',',')); NUM VAL -------------------- -------------------- 1111 val1 select * from table(FUNC1('1111,2222,121212',',')); NUM VAL -------------------- -------------------- 1111 val1 2222 val2 121212 val3 以显式调用该函数并处理异常:

func1

db<>fiddle demo

或者您可以更改create or replace FUNCTION FUNC1(num_list varchar2,separator varchar2) RETURN typeAs PIPELINED as l_val varchar2(20); begin FOR nums in (select regexp_substr(num_list,'[^'||separator||']+', 1, level) num from dual connect by regexp_substr(num_list, '[^'||separator||']+', 1, level) is not null) loop begin l_val := FUNC2(nums.num); exception when no_data_found then l_val := null; end; PIPE ROW(typeA(NVL(nums.num,0) ,NVL(l_val,0))); end loop; end; / select * from table(FUNC1('1111,4333,121212',',')); NUM VAL -------------------- -------------------- 1111 val1 4333 0 121212 val3 select * from table(FUNC1('1111,2222,121212',',')); NUM VAL -------------------- -------------------- 1111 val1 2222 val2 121212 val3 ,以便它捕获异常并返回null,或者更改其查询以使其一开始就无法获取异常。这是否合适取决于您-可以在需要传播异常的其他地方使用它...

(顺便说一下,由于func2返回一个字符串,因此func2也应该确实使用字符串-即使该字符串是nvl(),因为它已隐式转换为现在。)