Функция обратного вызова в 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 - это то, что мы должны избегать, если нет альтернативы. Здесь нет необходимости.