带有游标参数 oracle 的流水线函数
Posted
技术标签:
【中文标题】带有游标参数 oracle 的流水线函数【英文标题】:pipelined function with cursor parameter oracle 【发布时间】:2015-03-02 10:38:56 【问题描述】:例如,如果我有这种功能
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?
【问题讨论】:
您需要将rowsource
传递给流水线函数。游标只是指向结果集的指针。看我的回答。
【参考方案1】:
cursor main_cur is select 1 from dual;
游标是用于从结果集中获取行的指针。
因此,当您执行table(test_pipe(main_cur))
时,您不会将rowsource 传递给流水线函数。您需要先获取行,然后传递行源。
测试用例:
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>
【讨论】:
【参考方案2】:A cursor expression 相当于一个引用光标。 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 领域,因为这与您最初提出的问题无关,但从 cmets 看来,您似乎希望能够聚合光标中的数据;您可以改为使用分析计数来做到这一点。作为一个非常简单的示例,如果您的游标查询正在执行:
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.
【讨论】:
@arminrock - 没问题。正如您所说,我没有费心展示流水线功能,但我已经将它作为同一个包中的一个程序进行了测试,这似乎就是您正在做的事情。真的和拉利特一样,除了他在一个匿名的街区。 是的,“开放”有效,但老实说,我的主要问题是从显式光标中获取计数并将其分组。我用流水线函数写的,它在现实生活中看起来有点不同 select count(), trace into v_ct, v_trace from table(test_pipe(main_cur)) group by trace with count()=1;也许您可以建议一种更好的方法来从显式光标获取聚合,我只是不想一遍又一遍地重复选择,因为它太长了,这就是我使用显式光标的原因。 @arminrock - 我不确定我是否理解你的流水线函数在做什么,你创建它只是为了计数?如果您只想要计数为 1 的跟踪值,为什么不在显式游标查询中强制执行呢?或者您想对游标做些什么,并分别获取同一查询的计数?也许你正在尝试做的更完整的例子会有所帮助。 我将声明游标的结果集卸载到 .txt 文件中,但在此之前我需要获取 count(*) 并将其与列“trace”分组。所以 pipleined 函数只是为了得到那个聚合。我想我解释得很糟糕:( @arminrock - 也许您想获得分析计数作为游标查询的一部分?那时您不需要单独的聚合计数或单独的函数。以上是关于带有游标参数 oracle 的流水线函数的主要内容,如果未能解决你的问题,请参考以下文章