Я попытался сделать некоторое управление версиями для расчета зарплаты в нашем приложении для расчета заработной платы. Я сделал хранимую функцию для каждой версии формулы в соответствии с законодательством, которое применяется в любой момент времени, а затем я сохранил имена этих функций в таблице вместе со стартовой датой действия каждой функции. Затем я создал функцию, которая извлекает имя (и возвращает это имя как varchar) функции, применимой для формулы в данный момент времени. В представлении, которое делает все вычисления, я попытался вызвать эту функцию, чтобы получить имя функции и использовать это возвращенное имя для вызова функции формулы. Все это делается в команде выбора. Я пытаюсь вызвать функцию, имя которой возвращается другой функцией, например: (function1 (param1, param2, ...)) (paramx, paramy, ...) , но это не работает. Можно ли использовать имя, возвращаемое функцией1, для вызова функции с этим именем и с помощью ввода (параметры paramx, paramy, ...)?Как вызвать хранимую функцию, чье имя возвращается другой хранимой функцией в Oracle plsql?
ответ
Функции не являются первоклассными объектами, которые могут быть возвращены из других функций, а имя функции, содержащейся в переменной, не является фактическим кодом, который может быть выполнен. Однако вы, вероятно, можете сделать то, что вы пытаетесь сделать, используя динамический 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;
Удачи.
Функции не являются первоклассными объектами, а объектно-реляционными типами с функциями-членами. Теоретически вы можете создавать и хранить типы и использовать полиморфизм. Хотя на практике динамический SQL лучше 99% времени, даже если это не крутой объектно-ориентированный способ сделать это. –
@JonHeller - Если мы честны здесь, я должен признать, что я думаю, что вызывать функции, получая их имена из базы данных, а затем создавать блок BEGIN ... END, чтобы вызвать их динамически, звучит как кошмар обслуживания. Просто потому, что один МОЖЕТ сделать что-то не означает, что СЛЕДУЕТ ... :-) –
Если все функции, которые могут потребоваться для вызова, известны и существуют, когда основная функция скомпилирована, тогда вы можете использовать переменную, которую вы должны решить для вызова. Как очень грубый контур:
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 и позволяет иметь функции с разными номерами и/или типами аргументов, и это легче следовать тому, что происходит.
Если вы добавляете больше функций «на лету», вы, вероятно, не должны быть - по крайней мере, вне какого-либо механизма контроля и освобождения источника, что позволит вам поддерживать основную функцию на шаге. Вы могли бы, как падение назад, попробовать случай по умолчанию, чтобы выполнить любое имя функции, которое у вас есть динамически (как показывает Боб Джарвис), если это не то, что вы ожидаете; но вам нужны последовательные номера аргументов и типы данных, и это потенциально открывает уязвимость, если таблица, в которой вы получили имя функции, может быть изменена.
Я попробую это решение, потому что я не знаком с динамическим sql, а таблица с именами функций будет поддерживаться нашей разработкой и недоступны для других пользователей. Мы будем осторожны, чтобы также поддерживать и документировать главную функцию вместе с таблицей и функциями формулы. Большое спасибо. –
использовать «выполнить немедленный» в plsql. С строкой что-то вроде этого. "begin proc(); end;". Если вы вызываете это внутри функции, и если функция вызывается из выбора, убедитесь, что существует мутация. –
У всех ваших функций одинаковое количество и типы аргументов и одинаковый тип возвращаемого значения? –