Можно ли не передавать параметры, которые не имеют значения, по умолчанию?

Есть процедура с 21-им параметрoм, некоторые из них используются для передачи данных, другие - для получения или передачи\получения (в зависимости от обстоятельств). Причем, не все IN параметры обязательно передавать.

Выглядит, условно, так:

procedure FOO_BAR(
       a in number,
       b in number,
       c in out date,
       d in boolean,
       e in varchar2,
       ...
       z in varchar2
   ) is
begin
       otherProc(
           a, b, c, d, e, ..., z
       );
end;

Внутри нее вызывается другая процедура, в которую передаются эти параметры, она что-то делает, и в некоторые из них пишет результат.

К FOO_BAR я обращался из C#, создавал параметры через OracleParameter и тем, кому не обязательно задавать значение, просто не указывал Value. Но сами переменные-параметры при вызове передавал.

Теперь мне нужно как-то вызвать эту FOO_BAR не из C#-кода, а из другой хранимой процедуры, получить и вернуть значение параметра, например, c.

Проблема в том, что я не хочу объявлять 20 переменных под параметры, которые мне не нужны и передавать их только "чтобы было". Хочу что-то такое:

function FOO_BAR_LESS_PARAM(
       id number
   ) return date is
       newDate date;
begin
       FOO_BAR(
           a => id,
           c => newDate
       );
       
       return newDate;
end FOO_BAR_LESS_PARAM;

Т.е., передал только важный параметр, который нужен для расчетов, получил дату в переменную и вернул ее:

set serveroutput on;
declare
    id number := 111222;
    resDate date;
begin
    resDate := FOO_BAR_LESS_PARAM(id);
    dbms_output.put_line('resDate: ' || resDate);
end;

Можно ли как-то сделать это?

Желательно без задания значений по умолчанию, потому что я не знаю что будет, если в какой-нибудь параметр "b" передать 0, а не "ничего". Как я упоминал выше, в C# я вообще не указывал никакого значения и оно внутри там само как-то это интерпретировало. Сейчас ошибка о недостаче параметров при вызове FOO_BAR.


Ответы (2 шт):

Автор решения: 0xdb

Да, это возможно. Просто надо указать значение параметра по умолчанию NULL.

create or replace package pack as
    procedure foo (a in number, b in number, c in out date); 
    procedure bar (a in number, b in number := null, c in out date);
end;
/
create or replace package body pack as
    procedure foo (a in number, b in number, c in out date) is
    begin null;
    end;
    procedure bar (a in number, b in number := null, c in out date) is
        begin null;
    end;
end;
/

Посмотрите последние два рабочих вызова, они полностью идентичны, но во втором параметр передавать необязательно:

declare
    c date := date'2021-07-13';
begin 
    --pack.foo (1, c=>c);
    --PLS-00306: wrong number or types of arguments in call to 'FOO'
    pack.foo (1, b=>null, c=>c);
    pack.bar (1, c=>c);
end;
/
PL/SQL procedure successfully completed.
→ Ссылка
Автор решения: 0xdb

Без задания значений по умолчанию для неиспользующихся аргументов можно создавать процедуры с переменным количеством аргументов. В этом случае, аргументы реализуются через:

  1. тип данных - запись (не указанные аргументы имеют значение NULL)
  2. или ассоциативную коллекцию (не указанные аргументы просто отсутствуют)

Оба способа показанны в этом воспроизводимом примере:

declare
    type varargs is record (arg1 int, arg2 int, arg3 varchar2(8), arg4 date);
    type  kwargs is table of varchar2 (32) index by varchar2 (32);
    
    procedure foo (va varargs) is --, rc out sys_refcursor
        args varchar2(32767) := va.arg1||','||
                case when va.arg2 is not null then va.arg2||','end||
                case when va.arg3 is not null then va.arg3||','end||
                va.arg4;
    begin 
        dbms_output.put_line ('args='||args);    
    end;
    procedure foo (kw kwargs) is --, rc out sys_refcursor
        args varchar2(32767) := kw('arg1')||','||
                case when kw.exists('arg2') then kw('arg2')||','end||
                case when kw.exists('arg3') then kw('arg3')||','end||
                kw('arg4');
    begin 
        dbms_output.put_line ('args='||args);    
    end;

begin
    foo (varargs ( arg1 =>1,  arg3 =>'abc',  arg4 =>date'2021-07-19'));
    foo ( kwargs ('arg1'=>2, 'arg2'=>'def', 'arg4'=>date'2021-07-20'));
end;
/

Вывод результата:

args=1,abc,2021-07-19 00:00:00  
args=2,def,2021-07-20 00:00:00
→ Ссылка