简体   繁体   English

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

[英]pipelined function with cursor parameter oracle

for example if i have this kind of function 例如,如果我有这种功能

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

t_cursor is a ref cursor. t_cursor是一个引用游标。 i know i can call this function like 我知道我可以称这个功能为

select * from table(test_pipe(cursor(select 1 from dual)));

but what if i declare cursor in a package and want to pass it as an argument. 但是如果我在一个包中声明游标并希望将其作为参数传递该怎么办呢。 something like this. 这样的事情。

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;

And i get main_cur invalid identifier-- pl/sql:ORA00904 error. 我得到main_cur无效的标识符 - pl / sql:ORA00904错误。 How should i code to be able to pass the main_cur as an argument to test_pipe? 我应该如何编写能够将main_cur作为参数传递给test_pipe?

cursor main_cur is select 1 from dual; cursor main_cur从dual中选择1;

A cursor is a pointer used to fetch rows from a result set. 游标是用于从结果集中获取行的指针。

So, when you do table(test_pipe(main_cur)) , you are not passing a rowsource to the pipelined function . 所以,当你做table(test_pipe(main_cur))你是不是传递一个行源流水线功能 you need to first fetch the rows and then pass the rowsource. 您需要先获取行然后传递rowsource。

Test Case: 测试用例:

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>

Pipeline function 管道功能

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>

Now, let's test the pipelined function : 现在,让我们测试一下流水线函数

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>

A cursor expression is equivalent to a ref cursor. 游标表达式等效于ref游标。 An explicit cursor is a different and not interchangeable; 显式游标是不同的,不可互换; you can do some swapping between ref cursors and cursor variables with the dbms_sql package but not with an explicit cursor like this. 您可以使用dbms_sql包在ref游标和游标变量之间进行一些交换,但不能使用这样的显式游标进行交换。

The closest I can see to what you seem to want is to have a cursor variable that opens the same query with the `open for syntax : 我能看到的最接近你想要的是一个游标变量,用`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;

But that isn't quite the same thing, so might not be suitable. 但这不是一回事,所以可能不合适。 I'm not sure why you would want to do anything with an explicit cursor other than loop over it though. 我不知道你为什么要使用显式游标而不是循环覆盖它。


Straying into XY territory here as this is nothing to do with what you originally asked, but from comments you seem to want to be able to aggregate the data in the cursor; 因为这与你最初提出的问题没有任何关系,所以在这里直接进入XY领域,但是从评论中你似乎希望能够聚合光标中的数据; you could do that with an analytic count instead. 你可以用分析计数来做到这一点。 As a very simple example, if your cursor query was doing: 作为一个非常简单的示例,如果您的游标查询正在执行:

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

then you could add another column that counts each trace value: 然后你可以添加另一列来计算每个跟踪值:

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

You could then refer to column in your cursor loop. 然后,您可以引用游标循环中的列。 Or if you wanted to only loop over the rows where the count is one, your cursor could use that as a subquery: 或者,如果您只想循环计数为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 . SQL小提琴演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM