Функция обратного вызова в Oracle PL/SQL

Я делал некоторые преобразования / обработку данных в PL/SQL, и я хочу удалить дубликаты кода из моего пакета. Это соответствующие части кода.

Тип ввода для табличной функции:

type t_legs_cur is ref cursor return legs%rowtype;  

Процедура, которая обрабатывает одну запись:

procedure discontinuity_rule(p_leg in out nocopy legs%rowtype) as
begin
  null; --business logic here
end discontinuity_rule;

Табличная функция, которая перебирает курсор, обрабатывает каждую строку в курсорах и передает результат (если есть):

function apply_discontinuity_rule(p_cur t_legs_cur)
  return t_legs pipelined
  order p_cur by (/* some fields */)    
  parallel_enable (partition p_cur by range (/* some fields */))
as
  v_leg legs%rowtype;
begin
  loop
    fetch p_cur into v_leg;
    exit when p_cur%notfound;

    discontinuity_rule(v_leg); --call back

    if v_leg.id is not null then
      pipe row (v_leg);
    end if;

  end loop;
end apply_discontinuity_rule;

Есть несколько шагов преобразования / обработки, например, я бы запустил следующую команду select, чтобы выполнить некоторую обработку и применить некоторые правила в указанном порядке:

select * from table(trip_rules.generate_trips_from_legs(cursor(
  select * from table(trip_rules.apply_5_legs_rule(cursor(
    select * from table (trip_rules.apply_previous_city_rule(cursor(
      select * from table (trip_rules.apply_backhaul_rule(cursor(
        select * from table(trip_rules.apply_connection_time_rule(cursor(
          select * from table(trip_rules.apply_discontinuity_rule(cursor(
            select * from table(trip_rules.generate_legs_from_input(cursor(
              select * from INPUT_DATA
            )))
          )))
        )))
      )))
    )))
  )))
)));

Это все прекрасно, но проблема в том, что мой пакет trip_rule содержит много apply_*_rule функции. Все они похожи на пример apply_discontinuity_rule, Единственное отличие - это фактическая процедура (discontinuity_ruleони перезванивают

Итак, мой вопрос будет, как я могу избежать копирования кода apply_* функции. Есть ли более элегантный способ сделать это, тогда используйте большой, если: if p_rule_name == 'discontinuity_rule' then

function apply_rule(p_cur t_legs_cur, p_rule_name in varchar2)
  return t_legs pipelined
  order p_cur by (/* some fields */)    
  parallel_enable (partition p_cur by range (/* some fields */))
as
  v_leg legs%rowtype;
begin
  loop
    fetch p_cur into v_leg;
    exit when p_cur%notfound;

    if p_rule_name == 'discontinuity_rule' then
      discontinuity_rule(v_leg);
    elsif p_rule_name == 'other_rule' then
      other_rule(v_leg);
    elsif p_rule_name == 'totally_other_rule' then
      totally_other_rule(v_leg);
    -- and so on...
    end if;

    if v_leg.id is not null then
      pipe row (v_leg);
    end if;

  end loop;
end apply_rule;

Я также понимаю, что было бы возможно создать анонимный блок PL/SQL на лету, используя имя процедуры, и выполнить его как динамический SQL. Интересно, можно ли это сделать правильно, не убивая мое выступление. Любая идея приветствуется.

1 ответ

Решение

Ваше гигантское утверждение IF не является дублирующим кодом.

Правда, у него есть части, которые похожи друг на друга, но это...

elsif p_rule_name == 'other_rule' then
    other_rule(v_leg);

... определенно не то же самое, что это...

elsif p_rule_name == 'totally_other_rule' then
    totally_other_rule(v_leg); 

Динамический PL/SQL - это то, что мы должны избегать, если нет альтернативы. Здесь нет необходимости.

Другие вопросы по тегам