合并两个sys_refcursor的输出

时间:2018-11-01 16:36:35

标签: oracle11g merge cursor

我在oracle 11g中有两个函数,它们返回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

1 个答案:

答案 0 :(得分:1)

没有简单的内置机制来合并引用游标;它们本质上是指向结果集的指针,并且不能将它们视为表,因此无法将它们连接在一起,这实际上是您要在此处实现的目标。

如果只想显示合并的结果,则可以使用PL / SQL集合存储第一个ref游标的结果,然后根据{{1}使用第二个游标的结果进行更新/添加。 }是常用的“键”值:

leg

具有返回您显示的结果的虚拟函数的

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;
/

两个光标循环本质上是相同的。调用相关函数并循环遍历结果,在index-by集合元素中为游标具有的列设置值;在两种情况下,索引都是17,3, 18,2,1 PL/SQL procedure successfully completed. 值。

第一个循环在索引17和18处填充记录元素的legleg值。第二个循环仅看到18的结果并为该元素设置gettoni。如果那也有一个不同的interrogazioni,比如说19,那么它还将用同时包含legleg值的索引填充一个元素。 (因此,从本质上讲,它大致等同于完整的外部联接...)

但是,依靠interrogazioni进行输出并不理想,因为您无法控制客户端是否正在使用该格式,并且格式化和使用更加困难。将结果作为可以在查询中使用的表集合或作为新的引用游标取回,可能会更有用。

您可以使用包来定义集合类型,使用上述函数的函数将结果通过管道传递到表集合中,使用第二个函数从该管道表中生成引用游标:

dbms_output
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

如果您愿意,还可以使用架构级别的对象和表类型以及架构级别的函数来做到这一点:

select * from table(p42.num_combo_tab('MRTMRZ'));

       LEG    GETTONI INTERROGAZIONI
---------- ---------- --------------
        17          3               
        18          2              1

然后您可以将其称为:

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,而不是现有函数声明其参数的方式。