使用不确定数量的参数创建 Oracle function/macro

Create Oracle function/macro with an undeterminate number of arguments

是否可以创建 Oracle PL/SQL 函数或宏来帮助我生成一些代码?

例如

sumnull(a,b) 

会return

coalesce(a, 0) + coalesce(b, 0) +
        (case when coalesce(a, b) is not null then 0 else null end)

sumnull(a,b,c)

会return

coalesce(a, 0) + coalesce(b, 0) + coalesce(c, 0) +
        (case when coalesce(a, b, c ) is not null then 0 else null end)

但是 sumnull 也可以接受 3 个以上的参数 (a,b,c,d,e.....)

在 C varargs 意义上,您不能有可变数量的参数(例如)。你可以重载一个函数,所以你有一个版本需要 2 个,另一个版本需要 3 个,等等,这将是一个难以维护的问题;或者有一长串值,它们都默认为零:

create or replace function sumnull (p_1 number default null, p_2 number default null,
  p_3 number default null, p_4 number default null /*, etc. */)
return number as
begin
  return coalesce(p_1, 0) + coalesce(p_2, 0)
    + coalesce(p_3, 0) + coalesce(p_4, 0) /* + etc. */;
end;
/

select sumnull() from dual;

 SUMNULL()
----------
         0 

select sumnull(null) from dual;

SUMNULL(NULL)
-------------
            0 

select sumnull(1,null,7,9) from dual;

SUMNULL(1,NULL,7,9)
-------------------
                 17 

但在某些时候你仍然需要设置一个上限,如果你尝试发送太多参数,它会出错,PLS-00306。重复这些子句有点乏味且可能容易出错。

另一种选择是传递一组值,例如:

create or replace function sumnull (p_values sys.odcinumberlist)
return number as
  l_total number := 0;
begin
  if p_values is null or p_values.count = 0 then
    return l_total;
  end if;

  for i in 1..p_values.count loop
    l_total := l_total + coalesce(p_values(i), 0);
  end loop;

  return l_total;
end;
/

然后你可以这样称呼它:

select sumnull(null) from dual;

SUMNULL(NULL)
-------------
            0 

select sumnull(sys.odcinumberlist()) from dual;

SUMNULL(SYS.ODCINUMBERLIST())
-----------------------------
                            0 

select sumnull(sys.odcinumberlist(1,null,7,9)) from dual;

SUMNULL(SYS.ODCINUMBERLIST(1,NULL,7,9))
---------------------------------------
                                     17 

您也可以将列名作为较大查询的一部分传递;在此处对虚拟数据使用 CTE:

with t as (select 1 as a, null as b, 7 as c, 9 as d from dual)
select sumnull(sys.odcinumberlist(a, b, c, d)) from t;

SUMNULL(SYS.ODCINUMBERLIST(A,B,C,D))
------------------------------------
                                  17 

你可以在SQL级别定义你自己的集合类型当然,built-in sys.odcinumberlist只是方便。