2016-02-19 4 views
1

Я попытался сделать некоторое управление версиями для расчета зарплаты в нашем приложении для расчета заработной платы. Я сделал хранимую функцию для каждой версии формулы в соответствии с законодательством, которое применяется в любой момент времени, а затем я сохранил имена этих функций в таблице вместе со стартовой датой действия каждой функции. Затем я создал функцию, которая извлекает имя (и возвращает это имя как varchar) функции, применимой для формулы в данный момент времени. В представлении, которое делает все вычисления, я попытался вызвать эту функцию, чтобы получить имя функции и использовать это возвращенное имя для вызова функции формулы. Все это делается в команде выбора. Я пытаюсь вызвать функцию, имя которой возвращается другой функцией, например: (function1 (param1, param2, ...)) (paramx, paramy, ...) , но это не работает. Можно ли использовать имя, возвращаемое функцией1, для вызова функции с этим именем и с помощью ввода (параметры paramx, paramy, ...)?Как вызвать хранимую функцию, чье имя возвращается другой хранимой функцией в Oracle plsql?

+2

использовать «выполнить немедленный» в plsql. С строкой что-то вроде этого. "begin proc(); end;". Если вы вызываете это внутри функции, и если функция вызывается из выбора, убедитесь, что существует мутация. –

+1

У всех ваших функций одинаковое количество и типы аргументов и одинаковый тип возвращаемого значения? –

ответ

4

Функции не являются первоклассными объектами, которые могут быть возвращены из других функций, а имя функции, содержащейся в переменной, не является фактическим кодом, который может быть выполнен. Однако вы, вероятно, можете сделать то, что вы пытаетесь сделать, используя динамический 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; 

Удачи.

+0

Функции не являются первоклассными объектами, а объектно-реляционными типами с функциями-членами. Теоретически вы можете создавать и хранить типы и использовать полиморфизм. Хотя на практике динамический SQL лучше 99% времени, даже если это не крутой объектно-ориентированный способ сделать это. –

+0

@JonHeller - Если мы честны здесь, я должен признать, что я думаю, что вызывать функции, получая их имена из базы данных, а затем создавать блок BEGIN ... END, чтобы вызвать их динамически, звучит как кошмар обслуживания. Просто потому, что один МОЖЕТ сделать что-то не означает, что СЛЕДУЕТ ... :-) –

2

Если все функции, которые могут потребоваться для вызова, известны и существуют, когда основная функция скомпилирована, тогда вы можете использовать переменную, которую вы должны решить для вызова. Как очень грубый контур:

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

Если вы добавляете больше функций «на лету», вы, вероятно, не должны быть - по крайней мере, вне какого-либо механизма контроля и освобождения источника, что позволит вам поддерживать основную функцию на шаге. Вы могли бы, как падение назад, попробовать случай по умолчанию, чтобы выполнить любое имя функции, которое у вас есть динамически (как показывает Боб Джарвис), если это не то, что вы ожидаете; но вам нужны последовательные номера аргументов и типы данных, и это потенциально открывает уязвимость, если таблица, в которой вы получили имя функции, может быть изменена.

+0

Я попробую это решение, потому что я не знаком с динамическим sql, а таблица с именами функций будет поддерживаться нашей разработкой и недоступны для других пользователей. Мы будем осторожны, чтобы также поддерживать и документировать главную функцию вместе с таблицей и функциями формулы. Большое спасибо. –