Я попытался сделать управление версиями для расчета заработной платы в нашем приложении для расчета заработной платы. Я создал хранимую функцию для каждой версии формулы в соответствии с законодательством, которое применяется в любой момент времени, а затем я сохранил имена этих функций в таблице вместе с датой начала действия каждой функции. Затем я сделал функцию, которая извлекает имя (и возвращает это имя как varchar) функции, применимой к формуле в данный момент времени. В представлении, которое выполняет все вычисления, я попытался вызвать эту функцию, чтобы получить имя функции и использовать это возвращенное имя для вызова функции формулы. Все это сделано в инструкции select. Я пытаюсь вызвать функцию, имя которой возвращается другой функцией, например: (function1(param1, param2,...))(paramx, paramy,...), но это не работает. Есть ли способ использовать имя, возвращаемое функцией1, для вызова функции с этим именем и вводом (параметры paramx, paramy,...)?
Как вызвать хранимую функцию, имя которой возвращается другой хранимой функцией в Oracle plsql?
Ответы (2)
Функции не являются объектами первого класса, которые могут быть возвращены из других функций, и имя функции, содержащееся в переменной, не является фактическим кодом, который может быть выполнен. Однако вы, вероятно, можете сделать то, что пытаетесь сделать, используя динамический SQL:
DECLARE
param1 NUMBER;
param2 VARCHAR2(2000);
function_name VARCHAR2(2000);
paramx NUMBER;
paramy VARCHAR2(2000);
plsql_block VARCHAR2(2000);
result NUMBER; -- assumes the function returns a NUMBER
BEGIN
param1 := 123; -- or whatever is appropriate
param2 := 'abc'; -- or whatever is appropriate
function_name := function1(param1, param2);
-- assume that function_name now contains 'some_function'
paramx := 456; -- or whatever is appropriate
paramy := 'def'; -- or whatever is appropriate
plsql_block:= 'BEGIN :r := ' || function_name || '(:px, :py); END;';
-- plsql_block should now contain 'BEGIN :r := some_function(:px, :py); END;'
EXECUTE IMMEDIATE plsql_block USING IN OUT result, paramx, paramy;
DBMS_OUTPUT.PUT_LINE('result = ' || result);
END;
Удачи.
BEGIN...END
для их динамического вызова звучит как кошмар обслуживания. То, что человек МОЖЕТ что-то сделать, не означает, что он ДОЛЖЕН... :-)
- person Bob Jarvis - Reinstate Monica; 20.02.2016
Если все функции, которые вам, возможно, придется вызывать, известны и существуют на момент компиляции основной функции, вы можете использовать переменную, которую вам нужно решить, какую из них вызывать. В очень грубой схеме:
create function master_salary(p_date date)
return number as
l_function_name all_objects.object_name%type;
begin
l_function_name := choose_function(p_date);
case l_function
when 'function_a' then
return function_a;
when 'function_b' then
return function_b(some_arg);
when 'function_c' then
return function_c(some_arg, another_arg);
else
raise_application_error(-20001, 'Unknown function ' || l_function_name);
end case;
end;
/
Это позволяет избежать динамического SQL и позволяет вам иметь функции с разными номерами и/или типами аргументов, а также легче следить за тем, что происходит.
Если вы добавляете больше функций на лету, то вам, вероятно, не следует этого делать — по крайней мере, не за пределами какого-то механизма управления исходным кодом и выпуска, который позволит вам поддерживать основную функцию в шаге. Вы могли бы, в качестве запасного варианта, сделать так, чтобы случай по умолчанию пытался выполнить любое имя функции, которое у вас есть, динамически (как показывает Боб Джарвис), если это не то, что вы ожидаете; но вам понадобятся согласованные номера аргументов и типы данных, и это потенциально открывает уязвимость, если таблица, из которой вы получаете имя функции, может быть изменена.