合并两个 sys_refcursor 的输出
Merge the output of two sys_refcursor
我在 oracle 11g 中有两个函数,return 一个 sys_refcursos。
本次第一个
create or replace FUNCTION num_gettoni
(cf_parlamentare IN parlamentari.cf %TYPE DEFAULT 'MRTMRZ'
--, num_legislatura in legislature.id%TYPE
) RETURN SYS_REFCURSOR
AS
my_cursor SYS_REFCURSOR;
pippo legislature.id%type;
BEGIN
OPEN my_cursor FOR
select
leg,
ct as gettoni
from(
SELECT
l.id AS leg,
COUNT(*) - lead(COUNT(*), 1, 0) over (order by l.datainizio) AS ct
FROM
legislature l,
partecipazioni i,
parlamentari p
WHERE
i.sedute_data >= l.datainizio
AND p.cf = i.parlamentare
AND p.cf = cf_parlamentare
group by l.datainizio, l.id
)
where ct > 0
order by ct desc;
/*open my_cursor;
loop
pippo := my_cursor.leg;
END LOOP;
end loop;*/
RETURN my_cursor;
END num_gettoni;
第一个函数的输出示例是
select num_gettoni('MRTMRZ') from dual;
NUM_GETTONI('MRTMRZ')
---------------------
LEG GETTONI
---------------------- ----------------------
17 3
18 2
第二个函数类似,第二个函数的输出为
select num_interrogazioni('MRTMRZ') from dual;
NUM_INTERROGAZIONI('MRTMRZ')
--------------------------------------
LEG INTERROGAZIONI
---------------------- ----------------------
18 1
是否可以通过过程调用这些函数并得到类似如下的结果?
NUM_INTERROGAZIONI('MRTMRZ')
--------------------------------------
LEG GETTONI INTERROGAZIONI
---------------------- ---------------------- ----------------------
17 3
18 2 1
没有简单的内置机制来合并引用游标;它们本质上是指向结果集的指针,它们不能被视为 tables,所以它们不能被连接,这基本上就是您要在此处实现的目标。
如果您只想显示组合结果,您可以使用 PL/SQL 集合来存储第一个引用游标的结果,然后 update/add 将第二个引用游标的结果存储到它,基于 leg
是常见的 'key' 值:
declare
-- for the collection
type t_rec is record (leg number, gettoni number, interrogazioni number);
type t_tab is table of t_rec index by pls_integer;
l_tab t_tab;
-- for the cursors returned by the functions
l_cursor sys_refcursor;
-- for the individual columns from the cursors
l_leg number;
l_gettoni number;
l_interrogazioni number;
begin
l_cursor := num_gettoni('MRTMRZ');
loop
fetch l_cursor into l_leg, l_gettoni;
exit when l_cursor%notfound;
l_tab(l_leg).leg := l_leg;
l_tab(l_leg).gettoni := l_gettoni;
end loop;
close l_cursor;
l_cursor := num_interrogazioni('MRTMRZ');
loop
fetch l_cursor into l_leg, l_interrogazioni;
exit when l_cursor%notfound;
l_tab(l_leg).leg := l_leg;
l_tab(l_leg).interrogazioni := l_interrogazioni;
end loop;
close l_cursor;
for i in l_tab.first..l_tab.last loop
dbms_output.put_line(l_tab(i).leg ||','|| l_tab(i).gettoni ||','|| l_tab(i).interrogazioni);
end loop;
end;
/
使用虚拟函数 return 您显示的结果,得到:
17,3,
18,2,1
PL/SQL procedure successfully completed.
这两个游标循环本质上是一样的。调用相关函数并遍历结果,在索引集合元素中为游标具有的列设置值;在这两种情况下,索引都是 leg
值。
第一个循环为索引 17 和 18 处的记录元素填充 leg
和 gettoni
值。第二个循环只看到 18 的结果并为此设置 interrogazioni
元素。如果它也有一个不同的 leg
,比如 19,那么它也会用 leg
和 interrogazioni
值填充具有该索引的元素。 (所以,本质上,它大致相当于一个完整的外部连接...)
但是依赖 dbms_output
输出并不理想,因为您无法控制客户端是否正在使用它,而且它更难格式化和使用。将结果返回为可在查询中使用的 table 集合或可能作为新的引用游标可能会更有用。
您可以使用一个包来定义集合类型,其中一个函数使用上述机制将结果作为 table 集合通过管道输出,第二个函数从该管道生成一个引用游标table:
create or replace package p42 as
type t_rec is record (leg number, gettoni number, interrogazioni number);
type t_tab is table of t_rec;
-- function for pipelined table collection
function num_combo_tab (p_param varchar2) return t_tab pipelined;
-- function for ref cursor
function num_combo_cur (p_param varchar2) return sys_refcursor;
end p42;
/
create or replace package body p42 as
-- function for pipelined table collection
function num_combo_tab (p_param varchar2) return t_tab pipelined is
type t_tmp_tab is table of t_rec index by pls_integer;
l_tab t_tmp_tab;
l_leg number;
l_gettoni number;
l_interrogazioni number;
l_cursor sys_refcursor;
begin
l_cursor := num_gettoni(p_param);
loop
fetch l_cursor into l_leg, l_gettoni;
exit when l_cursor%notfound;
l_tab(l_leg).leg := l_leg;
l_tab(l_leg).gettoni := l_gettoni;
end loop;
close l_cursor;
l_cursor := num_interrogazioni(p_param);
loop
fetch l_cursor into l_leg, l_interrogazioni;
exit when l_cursor%notfound;
l_tab(l_leg).leg := l_leg;
l_tab(l_leg).interrogazioni := l_interrogazioni;
end loop;
close l_cursor;
for i in l_tab.first..l_tab.last loop
pipe row (l_tab(i));
end loop;
end num_combo_tab;
-- function for ref cursor
function num_combo_cur (p_param varchar2) return sys_refcursor is
l_cursor sys_refcursor;
begin
open l_cursor for
select * from table(num_combo_tab(p_param));
return l_cursor;
end num_combo_cur;
end p42;
/
这里的num_combo_tab
基本上是上面的匿名块,但是它管道记录类型而不是使用dbms_output
。然后 num_combo_cur
只是为该结果打开一个引用游标。
那么你可以这样做:
select p42.num_combo_cur('MRTMRZ') from dual;
P42.NUM_COMBO_CUR('M
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
LEG GETTONI INTERROGAZIONI
---------- ---------- --------------
17 3
18 2 1
或者直接使用table版本:
select * from table(p42.num_combo_tab('MRTMRZ'));
LEG GETTONI INTERROGAZIONI
---------- ---------- --------------
17 3
18 2 1
如果您愿意,您也可以使用架构级对象和 table 类型以及架构级函数来执行此操作:
create type t_obj as object (leg number, gettoni number, interrogazioni number)
/
create type t_tab is table of t_obj
/
create or replace function num_combo_tab (p_param varchar2)
return t_tab pipelined as
type t_tmp_tab is table of t_obj index by pls_integer;
l_tab t_tmp_tab;
l_leg number;
l_gettoni number;
l_interrogazioni number;
l_cursor sys_refcursor;
begin
l_cursor := num_gettoni(p_param);
loop
fetch l_cursor into l_leg, l_gettoni;
exit when l_cursor%notfound;
l_tab(l_leg) := new t_obj(l_leg, l_gettoni, null);
end loop;
close l_cursor;
l_cursor := num_interrogazioni(p_param);
loop
fetch l_cursor into l_leg, l_interrogazioni;
exit when l_cursor%notfound;
if l_tab.exists(l_leg) then
l_tab(l_leg).interrogazioni := l_interrogazioni;
else
l_tab(l_leg) := new t_obj(l_leg, null, l_interrogazioni);
end if;
end loop;
close l_cursor;
for i in l_tab.first..l_tab.last loop
pipe row (l_tab(i));
end loop;
end num_combo_tab;
/
那么你可以这样称呼它:
select * from table(num_combo_tab('MRTMRZ'));
LEG GETTONI INTERROGAZIONI
---------- ---------- --------------
17 3
18 2 1
但无论如何,将此功能(可能还有您的原始功能)放在一个包中可能更明智。
在以上所有内容中,很明显,请尽可能使用您自己的数据类型和 %type
,我没有您的 table,因此我使用了例如p_param varchar
而不是现有函数声明其参数的方式。
我在 oracle 11g 中有两个函数,return 一个 sys_refcursos。 本次第一个
create or replace FUNCTION num_gettoni
(cf_parlamentare IN parlamentari.cf %TYPE DEFAULT 'MRTMRZ'
--, num_legislatura in legislature.id%TYPE
) RETURN SYS_REFCURSOR
AS
my_cursor SYS_REFCURSOR;
pippo legislature.id%type;
BEGIN
OPEN my_cursor FOR
select
leg,
ct as gettoni
from(
SELECT
l.id AS leg,
COUNT(*) - lead(COUNT(*), 1, 0) over (order by l.datainizio) AS ct
FROM
legislature l,
partecipazioni i,
parlamentari p
WHERE
i.sedute_data >= l.datainizio
AND p.cf = i.parlamentare
AND p.cf = cf_parlamentare
group by l.datainizio, l.id
)
where ct > 0
order by ct desc;
/*open my_cursor;
loop
pippo := my_cursor.leg;
END LOOP;
end loop;*/
RETURN my_cursor;
END num_gettoni;
第一个函数的输出示例是
select num_gettoni('MRTMRZ') from dual;
NUM_GETTONI('MRTMRZ')
---------------------
LEG GETTONI
---------------------- ----------------------
17 3
18 2
第二个函数类似,第二个函数的输出为
select num_interrogazioni('MRTMRZ') from dual;
NUM_INTERROGAZIONI('MRTMRZ')
--------------------------------------
LEG INTERROGAZIONI
---------------------- ----------------------
18 1
是否可以通过过程调用这些函数并得到类似如下的结果?
NUM_INTERROGAZIONI('MRTMRZ')
--------------------------------------
LEG GETTONI INTERROGAZIONI
---------------------- ---------------------- ----------------------
17 3
18 2 1
没有简单的内置机制来合并引用游标;它们本质上是指向结果集的指针,它们不能被视为 tables,所以它们不能被连接,这基本上就是您要在此处实现的目标。
如果您只想显示组合结果,您可以使用 PL/SQL 集合来存储第一个引用游标的结果,然后 update/add 将第二个引用游标的结果存储到它,基于 leg
是常见的 'key' 值:
declare
-- for the collection
type t_rec is record (leg number, gettoni number, interrogazioni number);
type t_tab is table of t_rec index by pls_integer;
l_tab t_tab;
-- for the cursors returned by the functions
l_cursor sys_refcursor;
-- for the individual columns from the cursors
l_leg number;
l_gettoni number;
l_interrogazioni number;
begin
l_cursor := num_gettoni('MRTMRZ');
loop
fetch l_cursor into l_leg, l_gettoni;
exit when l_cursor%notfound;
l_tab(l_leg).leg := l_leg;
l_tab(l_leg).gettoni := l_gettoni;
end loop;
close l_cursor;
l_cursor := num_interrogazioni('MRTMRZ');
loop
fetch l_cursor into l_leg, l_interrogazioni;
exit when l_cursor%notfound;
l_tab(l_leg).leg := l_leg;
l_tab(l_leg).interrogazioni := l_interrogazioni;
end loop;
close l_cursor;
for i in l_tab.first..l_tab.last loop
dbms_output.put_line(l_tab(i).leg ||','|| l_tab(i).gettoni ||','|| l_tab(i).interrogazioni);
end loop;
end;
/
使用虚拟函数 return 您显示的结果,得到:
17,3,
18,2,1
PL/SQL procedure successfully completed.
这两个游标循环本质上是一样的。调用相关函数并遍历结果,在索引集合元素中为游标具有的列设置值;在这两种情况下,索引都是 leg
值。
第一个循环为索引 17 和 18 处的记录元素填充 leg
和 gettoni
值。第二个循环只看到 18 的结果并为此设置 interrogazioni
元素。如果它也有一个不同的 leg
,比如 19,那么它也会用 leg
和 interrogazioni
值填充具有该索引的元素。 (所以,本质上,它大致相当于一个完整的外部连接...)
但是依赖 dbms_output
输出并不理想,因为您无法控制客户端是否正在使用它,而且它更难格式化和使用。将结果返回为可在查询中使用的 table 集合或可能作为新的引用游标可能会更有用。
您可以使用一个包来定义集合类型,其中一个函数使用上述机制将结果作为 table 集合通过管道输出,第二个函数从该管道生成一个引用游标table:
create or replace package p42 as
type t_rec is record (leg number, gettoni number, interrogazioni number);
type t_tab is table of t_rec;
-- function for pipelined table collection
function num_combo_tab (p_param varchar2) return t_tab pipelined;
-- function for ref cursor
function num_combo_cur (p_param varchar2) return sys_refcursor;
end p42;
/
create or replace package body p42 as
-- function for pipelined table collection
function num_combo_tab (p_param varchar2) return t_tab pipelined is
type t_tmp_tab is table of t_rec index by pls_integer;
l_tab t_tmp_tab;
l_leg number;
l_gettoni number;
l_interrogazioni number;
l_cursor sys_refcursor;
begin
l_cursor := num_gettoni(p_param);
loop
fetch l_cursor into l_leg, l_gettoni;
exit when l_cursor%notfound;
l_tab(l_leg).leg := l_leg;
l_tab(l_leg).gettoni := l_gettoni;
end loop;
close l_cursor;
l_cursor := num_interrogazioni(p_param);
loop
fetch l_cursor into l_leg, l_interrogazioni;
exit when l_cursor%notfound;
l_tab(l_leg).leg := l_leg;
l_tab(l_leg).interrogazioni := l_interrogazioni;
end loop;
close l_cursor;
for i in l_tab.first..l_tab.last loop
pipe row (l_tab(i));
end loop;
end num_combo_tab;
-- function for ref cursor
function num_combo_cur (p_param varchar2) return sys_refcursor is
l_cursor sys_refcursor;
begin
open l_cursor for
select * from table(num_combo_tab(p_param));
return l_cursor;
end num_combo_cur;
end p42;
/
这里的num_combo_tab
基本上是上面的匿名块,但是它管道记录类型而不是使用dbms_output
。然后 num_combo_cur
只是为该结果打开一个引用游标。
那么你可以这样做:
select p42.num_combo_cur('MRTMRZ') from dual;
P42.NUM_COMBO_CUR('M
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
LEG GETTONI INTERROGAZIONI
---------- ---------- --------------
17 3
18 2 1
或者直接使用table版本:
select * from table(p42.num_combo_tab('MRTMRZ'));
LEG GETTONI INTERROGAZIONI
---------- ---------- --------------
17 3
18 2 1
如果您愿意,您也可以使用架构级对象和 table 类型以及架构级函数来执行此操作:
create type t_obj as object (leg number, gettoni number, interrogazioni number)
/
create type t_tab is table of t_obj
/
create or replace function num_combo_tab (p_param varchar2)
return t_tab pipelined as
type t_tmp_tab is table of t_obj index by pls_integer;
l_tab t_tmp_tab;
l_leg number;
l_gettoni number;
l_interrogazioni number;
l_cursor sys_refcursor;
begin
l_cursor := num_gettoni(p_param);
loop
fetch l_cursor into l_leg, l_gettoni;
exit when l_cursor%notfound;
l_tab(l_leg) := new t_obj(l_leg, l_gettoni, null);
end loop;
close l_cursor;
l_cursor := num_interrogazioni(p_param);
loop
fetch l_cursor into l_leg, l_interrogazioni;
exit when l_cursor%notfound;
if l_tab.exists(l_leg) then
l_tab(l_leg).interrogazioni := l_interrogazioni;
else
l_tab(l_leg) := new t_obj(l_leg, null, l_interrogazioni);
end if;
end loop;
close l_cursor;
for i in l_tab.first..l_tab.last loop
pipe row (l_tab(i));
end loop;
end num_combo_tab;
/
那么你可以这样称呼它:
select * from table(num_combo_tab('MRTMRZ'));
LEG GETTONI INTERROGAZIONI
---------- ---------- --------------
17 3
18 2 1
但无论如何,将此功能(可能还有您的原始功能)放在一个包中可能更明智。
在以上所有内容中,很明显,请尽可能使用您自己的数据类型和 %type
,我没有您的 table,因此我使用了例如p_param varchar
而不是现有函数声明其参数的方式。