Oracle管道行函数中的游标

时间:2015-03-10 11:40:15

标签: oracle

我有一个像这样的流水线功能:

pipe row(mytype('1','1','1'));
pipe row(mytype('2','2','2'));
pipe row(mytype('3','3','3'));
pipe row(mytype('4','4','4'));
return;

我还有另一个使用游标读取此过程的过程:

for c_cursor in(
  SELECT field1 FROM table(mytable)) 
loop
  v_Var1:=c_cursor.field1;
  if((v_Var1 = '1')) then
    return;
  end if;
end loop;

我需要知道Oracle是否会在return之后处理其他行(2,3和4),否则它将停止管道。

感谢。

1 个答案:

答案 0 :(得分:2)

这很容易测试:

create function pipetest return sys.odcinumberlist pipelined as
begin
  for i in 1..5 loop
    pipe row(i);
    dbms_output.put_line('Piped ' || i);
  end loop;
  return;
end;
/

set serveroutput on size unlimited
begin
  for r in (select * from table(pipetest)) loop
    dbms_output.put_line('Got ' || r.column_value);
    return;
  end loop;
end loop;
/

anonymous block completed
Piped 1
Piped 2
Piped 3
Piped 4
Piped 5
Got 1

但是有多少行取决于获取大小;如果你管道1000行代替:

create function pipetest return sys.odcinumberlist pipelined as
begin
  for i in 1..1000 loop
...

然后(对我来说)它在第一次批量获取后停止:

anonymous block completed
Piped 1
Piped 2
Piped 3
... <snipped for brevity> ...
Piped 97
Piped 98
Piped 99
Got 1

因此,在调用块开始遍历它们之前,第一次获取有100行。如果我改变以后发生的回报:

if r.column_value = 101 then
  return;
end if;

然后我看到了:

anonymous block completed
Piped 1
Piped 2
Piped 3
...
Piped 97
Piped 98
Piped 99
Got 1
Got 2
Got 3
...
Got 96
Got 97
Got 98
Got 99
Got 100
Piped 100
Piped 101
Piped 102
Piped 103
...
Piped 197
Piped 198
Piped 199
Got 101

因此函数可能会在调用者返回后处理更多行,但它不一定会处理所有行。

正如您在评论中提到的,如果您打开游标并一次获取一行,它的行为会有所不同:

set serveroutput on size unlimited
declare
  cursor c is select * from table(pipetest);
  n number;
begin
  open c;
  loop
    fetch c into n;
    exit when c%notfound;
    dbms_output.put_line('Got ' || n);
    if n = 3 then
      return;
    end if;
  end loop;
  close c;
end loop;
/

anonymous block completed
Got 1
Piped 1
Got 2
Piped 2
Got 3

停止提取时,该功能仍会停止处理。这里唯一的区别是获取大小为1.对于批量收集,它的行为类似于原始的'for'循环,但您可以使用limit子句来查看具有的效果;

set serveroutput on size unlimited
declare
  cursor c is select * from table(pipetest);
  t sys.odcinumberlist;
begin
  open c;
  loop
    fetch c bulk collect into t limit 10;
    for i in 1..t.count loop
      dbms_output.put_line('Got ' || t(i));
      if t(i) = 3 then
        return;
      end if;
    end loop;
    exit when t.count < 10;
  end loop;
  close c;
end loop;
/

anonymous block completed
Piped 1
Piped 2
Piped 3
Piped 4
Piped 5
Piped 6
Piped 7
Piped 8
Piped 9
Got 1
Got 2
Got 3

如果您担心该功能产生的副作用,那么阻止它处理超出调用者停止条件的唯一方法就是进行单行提取。