Рефакторинг PL / SQL: множество курсоров с одинаковым типом строки (теоретически) - PullRequest
3 голосов
/ 17 мая 2011

Я пишу какой-нибудь PL / SQL и обнаружил, что попадаю в повторяющийся шаблон:

cursor c_curs1 is
   select a, b, c
   from (...) big_subquery_1
   where big_subquery_1.a_ind = 'Y'

cursor c_curs2 is
   select a, b, c
   from (...) big_subquery_2
   where big_subquery_2.b_ind = 'R'

cursor c_curs3 is
   select a, b, c
   from (...) big_subquery_3
   where big_subquery_3.c_ind = 'M'

...
type t_curs1_tab is table of c_curs1;
type t_curs2_tab is table of c_curs2;
type t_curs3_tab is table of c_curs3;
...
v_curs1_results t_curs1_tab := t_curs1_tab();
v_curs2_results t_curs2_tab := t_curs2_tab();
v_curs3_results t_curs3_tab := t_curs3_tab();

Затем, при обработке результатов, у меня есть такой код:

    open c_curs1;
    fetch c_curs1 bulk collect into v_curs1_results;
    close c_curs1;

    if v_curs1_results.first is not null and v_curs1_results.last is not null then
       for i in v_curs1_results.first .. v_curs1_results.last loop
           /*Do something with field a in the results
             Do something with field b in the results
             Do something with field c in the results*/
           ....
       end loop;
    end if;

код в цикле обработки одинаков для всех курсоров, так как все 3 курсора возвращают a,b,c - единственное отличие состоит в том, на какой курсор ссылается.Я хотел преобразовать это в какой-то типовой процессор набора результатов, но я застрял здесь:

procedure sp_process_collection(in_collection t_curs1_tab) is ...

Я могу вызвать это только с помощью v_curs1_results, я не могу вызвать это с помощью v_curs2_results или я получаю PLS-00306 wrong number of types or arguments... ошибку компилятора.Есть ли способ сделать это в общем, поэтому мне нужно написать только одну процедуру обработки коллекции?У меня такой шаблон курсора (возвращающий те же три столбца, всегда одинаковые типы) появляется в нескольких других частях одного и того же пакета и в цикле обработки, хотя семантически то же самое иногда пишется с немного другим кодом.Мне бы очень хотелось централизовать обработку в одной процедуре, я просто смог бы выяснить, как это сделать в PL / SQL.Я знаю, что PL / SQL не имеет обобщений (которые, как я думаю сделали бы решение Java / C # достаточно тривиальным), но мне интересно, есть ли другой способ решения этой проблемы, которого у меня просто нет?t думал о.

(используя Oracle 10g)

Ответы [ 4 ]

4 голосов
/ 17 мая 2011

Если результирующие столбцы совпадают, нет причин иметь три объявления TYPE. У тебя просто один ТИП. Нужна ли вам одна или несколько переменных этого типа, зависит от того, нужно ли вам одновременно хранить разные наборы данных.

cursor c_curs1 is
   select a, b, c
   from (...) big_subquery_1
   where big_subquery_1.a_ind = 'Y'

cursor c_curs2 is
   select a, b, c
   from (...) big_subquery_2
   where big_subquery_2.b_ind = 'R'

cursor c_curs3 is
   select a, b, c
   from (...) big_subquery_3
   where big_subquery_3.c_ind = 'M'

...
type t_curs_tab is table of c_curs1;
...
v_curs_results t_curs_tab := t_curs_tab();
...
open c_curs1;
fetch c_curs1 bulk collect into v_curs_results;
close c_curs1;
...
open c_curs2;
fetch c_curs2 bulk collect into v_curs_results;
close c_curs2;
...
open c_curs3;
fetch c_curs3 bulk collect into v_curs_results;
close c_curs3;
2 голосов
/ 17 мая 2011

Можете ли вы сделать это с помощью REF CURSOR?

Что-то вроде:

CREATE PROCEDURE sp_process_cursor(in_cursor SYS_REFCURSOR)

/* you don't need to open the cursor, it's already open */
FETCH in_cursor BULK COLLECT INTO v_cursor_results;
IF v_cursor_results.first is not null and v_cursor_results.last IS NOT NULL THEN
  FOR i in v_cursor_results.FIRST .. v_cursor_results.LAST LOOP
  ...
  END LOOP;
END IF;

Ваш код вызова должен вызывать эту процедуру один раз для курсора:

OPEN c_curs1;
sp_process_cursor(c_curs1);
CLOSE c_curs1;

OPEN c_curs2;
sp_process_cursor(c_curs2);
...
2 голосов
/ 17 мая 2011

Если вы хотите и можете сделать это, вы можете создать TYPE для представления записи, возвращаемой любым из курсоров.Например:

CREATE TYPE TRIPLE_TYPE IS OBJECT
(
  a NUMBER,
  b NUMBER,
  c NUMBER
);

И другой тип для хранения коллекции TRIPLE_TYPE:

CREATE TYPE TRIPLES_TYPE IS TABLE OF TRIPLE_TYPE;

Наконец, вы определяете свои курсоры для возврата TRIPLE_TYPE записей:

DECLARE

  cursor c_curs1 is
    select TRIPLE_TYPE(a, b, c)
    from (...) big_subquery_1
    where big_subquery_1.a_ind = 'Y';

  triples TRIPLES_TYPE;

BEGIN
  OPEN c_curs1;
  FETCH c_curs1 BULK COLLECT INTO triples;
  CLOSE c_curs1;
END;

Этот метод позволяет написать процедуру, которая принимает коллекцию TRIPLES_TYPE:

procedure sp_process_collection(in_collection TRIPLES_TYPE) is ...
0 голосов
/ 17 мая 2011

Похоже, у вас должно быть 3 курсора, потому что "big_subquery" в каждом отличается, я полагаю. Итак, вам действительно нужно централизовать процедуру обработки результатов a, b и c. Ничего особенного, просто определите локальную процедуру, чтобы сделать это:

CREATE or replace procedure my_proc IS

  cursor c_curs1 is
   select a, b, c
   from (...) big_subquery_1
   where big_subquery_1.a_ind = 'Y';

  cursor c_curs2 is
   select a, b, c
   from (...) big_subquery_2
   where big_subquery_2.b_ind = 'R';

  cursor c_curs3 is
   select a, b, c
   from (...) big_subquery_3
   where big_subquery_3.c_ind = 'M';

  -- local procedure to handle processing of a,b,c "types"
  procedure process_type(i_type in varchar2) is
  begin
    -- do something great here
  end process_type;

BEGIN
  for rec in c_curs1
  loop
    process_type(rec.a);
    -- do something else
    process_type(rec.b);
    -- do something more
    process_type(rec.c);
    -- do something even more
  end loop;

  for rec in c_curs2
  loop
    -- do processing for this cursor
    -- use process_type like above
  end loop;

  for rec in c_curs3
  loop
    -- do processing for this cursor
    -- use process_type like above
  end loop;

END;

Конечно, если вам нужно обрабатывать все 3 типа вместе для каждой строки, или если типы разные (varchar2, date и number), просто измените процедуру process_type для передачи всех 3 (a, b и с). Что-то вроде:

procedure process_type(i_type_a in varchar2, i_type_b in date, i_type_c in number) is
  begin
    -- do something great here
  end process_type;

И вы можете сделать это функцией, если вам нужно возвращаемое значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...