带有游标参数 oracle 的流水线函数

pipelined function with cursor parameter oracle

比如我有这种功能

function test_pipe(p_source in t_cursor)
return t_tab
pipelined
as --some code goes here

t_cursor 是一个引用游标。 我知道我可以像

这样调用这个函数
select * from table(test_pipe(cursor(select 1 from dual)));

但是如果我在包中声明游标并想将其作为参数传递怎么办。 像这样。

procedure test is
v_ct pls_integer;
cursor main_cur is select 1 from dual;
begin
select count(*) into v_ct from table(test_pipe(main_cur));
--some code
end;

我得到 main_cur 无效标识符 -- pl/sql:ORA00904 错误。 我应该如何编码才能将 main_cur 作为参数传递给 test_pipe?

A cursor expression is equivalent to a ref cursor. An explicit cursor 是不同的,不可互换;您可以使用 dbms_sql 包在引用游标和游标变量之间进行一些交换,但不能使用像这样的显式游标。

我能看到的最接近您似乎想要的是有一个游标变量,它打开与 the `open for syntax:

相同的查询
procedure test is
  v_ct pls_integer;
  main_cur t_cursor;
begin
  open main_cur for select 1 from dual;
  select count(*) into v_ct from table(test_pipe(main_cur));
  close main_cur;
  dbms_output.put_line('Count is: ' || v_ct);
  --some code
end test;

但这不是一回事,所以可能不合适。我不确定为什么你想要用一个明确的游标做任何事情而不是在它上面循环。


在这里偏离了 XY 领域,因为这与您最初的要求无关,但从评论来看,您似乎希望能够聚合游标中的数据;您可以改为使用分析计数来做到这一点。作为一个非常简单的示例,如果您的游标查询正在执行:

select trace, col1
from t42
order by trace, col1;

然后您可以添加另一列来计算每个跟踪值:

select trace, col1,
  count(col1) over (partition by trace) as trace_count
from t42
order by trace, col1;

然后您可以在游标循环中引用列。或者,如果您只想遍历计数为 1 的行,您的游标可以将其用作子查询:

select trace, col1
from (
  select trace, col1,
    count(col1) over (partition by trace) as trace_count
  from t42
)
where trace_count = 1
order by trace, col1;

SQL Fiddle demo.

cursor main_cur is select 1 from dual;

游标是用于从结果集中获取行的指针。

因此,当您执行 table(test_pipe(main_cur)) 时,您并未将 行源 传递给 流水线函数 。您需要先获取行,然后传递行源。

测试用例:

SQL> CREATE or replace TYPE target_table_row
  2  AS
  3    OBJECT
  4    ( EMPNO NUMBER(4) ,
  5      ENAME VARCHAR2(10)
  6      )
  7  /

Type created.

SQL>
SQL> sho err
No errors.
SQL>
SQL> CREATE or replace TYPE target_table_rows
  2  AS
  3    TABLE OF target_table_row;
  4  /

Type created.

SQL>
SQL> sho err
No errors.
SQL>

管道函数

SQL> CREATE OR REPLACE FUNCTION pipelined_fx(
  2      p_cursor IN SYS_REFCURSOR)
  3    RETURN target_table_rows PIPELINED PARALLEL_ENABLE(
  4      PARTITION p_cursor BY ANY)
  5  IS
  6  TYPE cursor_ntt
  7  IS
  8    TABLE OF emp%ROWTYPE;
  9    nt_src_data cursor_ntt;
 10  BEGIN
 11    LOOP
 12      FETCH p_cursor BULK COLLECT INTO nt_src_data LIMIT 100;
 13      FOR i IN 1 .. nt_src_data.COUNT
 14      LOOP
 15        PIPE ROW (target_table_row( nt_src_data(i).empno, nt_src_data(i).ename ));
 16      END LOOP;
 17      EXIT
 18    WHEN p_cursor%NOTFOUND;
 19    END LOOP;
 20    CLOSE p_cursor;
 21    RETURN;
 22  END pipelined_fx;
 23  /

Function created.

SQL>
SQL> show errors
No errors.
SQL>

现在,让我们测试流水线函数

SQL> DECLARE
  2    rc SYS_REFCURSOR;
  3    num NUMBER;
  4  BEGIN
  5    OPEN RC FOR SELECT * FROM emp;
  6    SELECT count(*) INTO num FROM TABLE(pipelined_fx(rc));
  7    DBMS_OUTPUT.PUT_LINE( num || ' rows in total.' );
  8  END;
  9  /
14 rows in total.

PL/SQL procedure successfully completed.

SQL>