Объединить выходные данные двух sys_refcursor - PullRequest
0 голосов
/ 01 ноября 2018

В 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 голосов
/ 02 ноября 2018

Нет простого встроенного механизма для объединения ref-курсоров; по сути, они являются указателями на наборы результатов, и их нельзя рассматривать как таблицы, поэтому их нельзя объединять, чего, по сути, вы и здесь добиваетесь.

Если вы просто хотите отобразить объединенные результаты, вы можете использовать коллекцию PL / SQL для хранения результатов из первого курсора ссылки, а затем обновить / добавить к нему результаты второго, исходя из того, что 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;
/

который с фиктивными функциями, возвращающими результаты, которые вы показали, получает:

17,3,
18,2,1


PL/SQL procedure successfully completed.

Два цикла курсора по сути одинаковы. Вызовите соответствующую функцию и переберите результаты, установив значения в элементе коллекции index-by для столбцов, которые имеет курсор; где в обоих случаях индексом является значение leg.

Первый цикл заполняет значения leg и gettoni для элементов записи по индексам 17 и 18. Второй просматривает результат только для 18 и устанавливает interrogazioni для этого элемента. Если бы это также имело другой leg, скажем, 19, то он также заполнил бы элемент с этим индексом значениями leg и interrogazioni. (Так что, по сути, это примерно эквивалентно полному внешнему объединению ...)

Но полагаться на dbms_output для вывода не идеально, так как вы не контролируете, использует ли это клиент, и его сложнее форматировать и потреблять. Вероятно, было бы более полезно вернуть результат в виде коллекции таблиц, которую можно использовать в запросе, или, возможно, в качестве нового курсора ref.

Вы можете использовать пакет для определения типов коллекций, при этом функция, использующая механизм, описанный выше, помещает результаты в виде коллекции таблиц, и вторая функция, которая генерирует курсор ref из этой переданной по конвейеру таблицы:

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, когда вы можете, у меня нет ваших таблиц, поэтому я использовал, например. p_param varchar вместо того, как существующие функции объявляют свои параметры.

...