【问题标题】:Optional argument in PL/pgSQL functionPL/pgSQL 函数中的可选参数
【发布时间】:2012-07-16 04:36:39
【问题描述】:

我正在尝试编写一个带有可选参数的 PL/pgSQL 函数。它基于过滤的记录集(如果指定)执行查询,否则对表中的整个数据集执行查询。

例如(伪代码)

CREATE OR REPLACE FUNCTION foofunc(param1 integer, param2 date, param2 date, optional_list_of_ids=[]) RETURNS SETOF RECORD AS $$
    IF len(optional_list_of_ids) > 0 THEN
        RETURN QUERY (SELECT * from foobar where f1=param1 AND f2=param2 AND id in optional_list_of_ids);
    ELSE
        RETURN QUERY (SELECT * from foobar where f1=param1 AND f2=param2);
    ENDIF
$$ LANGUAGE SQL;

实现此功能的正确方法是什么?

顺便说一句,我想知道如何在另一个外部函数中调用这样的函数。我就是这样做的——它是正确的,还是有更好的方法?

CREATE FUNCTION foofuncwrapper(param1 integer, param2 date, param2 date) RETURNS SETOF RECORD AS $$
BEGIN
   CREATE TABLE ids AS SELECT id from foobar where id < 100;
   RETURN QUERY (SELECT * FROM foofunc(param1, param2, ids));
END
$$ LANGUAGE SQL

【问题讨论】:

    标签: postgresql stored-procedures parameters parameter-passing plpgsql


    【解决方案1】:

    自 PostgreSQL 8.4(您似乎正在运行)以来,有 default values for function parameters。如果你把你的参数放在最后并提供一个默认值,你可以简单地从调用中省略它:

    CREATE OR REPLACE FUNCTION foofunc(_param1 integer
                                     , _param2 date
                                     , _ids    int[] DEFAULT '{}')
      RETURNS SETOF foobar         -- declare return type!
      LANGUAGE plpgsql AS
    $func$
    BEGIN  -- required for plpgsql
       IF _ids <> '{}'::int[] THEN  -- exclude empty array and NULL
          RETURN QUERY
          SELECT *
          FROM   foobar
          WHERE  f1 = _param1
          AND    f2 = _param2
          AND    id = ANY(_ids);    -- "IN" is not proper syntax for arrays
       ELSE
          RETURN QUERY
          SELECT *
          FROM   foobar
          WHERE  f1 = _param1
          AND    f2 = _param2;
       END IF;
    END  -- required for plpgsql
    $func$;
    

    要点:

    • 关键字DEFAULT用于声明参数默认值。简称:=

    • 我从凌乱的例子中删除了多余的param1

    • 由于您返回SELECT * FROM foobar,因此将返回类型声明为RETURNS SETOF foobar 而不是RETURNS SETOF record。带有匿名记录的后一种形式非常笨拙,您必须在每次调用时提供一个列定义列表。

    • 我使用整数数组 (int[]) 作为函数参数。相应地调整了IF 表达式和WHERE 子句。

    • IF 语句在普通 SQL 中不可用。必须是LANGUAGE plpgsql

    拨打或不拨打_ids:

    SELECT * FROM foofunc(1, '2012-1-1'::date);
    

    实际上是一样的:

    SELECT * FROM foofunc(1, '2012-1-1'::date, '{}'::int[]);
    

    您必须确保调用是明确的。如果你有另一个同名的函数和两个参数,Postgres 可能不知道该选择哪个。显式转换(就像我演示的那样)缩小了范围。否则,无类型的字符串文字也可以工作,但显式永远不会受到伤害。

    从另一个函数中调用:

    CREATE FUNCTION foofuncwrapper(_param1 integer, _param2 date)
      RETURNS SETOF foobar
      LANGUAGE plgpsql AS
    $func$
    DECLARE
       _ids int[] := '{1,2,3}';
    BEGIN
       -- whatever
    
       RETURN QUERY
       SELECT * FROM foofunc(_param1, _param2, _ids);
    END
    $func$;
    

    【讨论】:

    • +1 用于实际回答问题。这正是我想要的!
    【解决方案2】:

    详细阐述Frank 在此线程上的回答:

    VARIADIC 参数不必是唯一的参数,只能是最后一个参数。

    您可以将VARIADIC 用于可能采用零可变参数的函数,这只是有点复杂,因为它需要零参数的不同调用样式。您可以提供一个包装函数来隐藏丑陋。给定一个初始的 varardic 函数定义,如:

    CREATE OR REPLACE FUNCTION foofunc(param1 integer, param2 date, param2 date, optional_list_of_ids VARIADIC integer[]) RETURNS SETOF RECORD AS $$
    ....
    $$ language sql;
    

    对于零参数,使用如下包装器:

    CREATE OR REPLACE FUNCTION foofunc(integer, date, date) RETURNS SETOF RECORD AS $body$
    SELECT foofunc($1,$2,$3,VARIADIC ARRAY[]::integer[]);
    $body$ LANGUAGE 'sql';
    

    或者直接用一个空数组(如VARIADIC '{}'::integer[])调用主函数。包装器很丑,但它包含丑陋,所以我建议使用包装器。

    可以以可变形式进行直接调用:

    SELECT foofunc(1,'2011-01-01','2011-01-01', 1, 2, 3, 4);
    

    ...或带有数组ctor的数组调用形式:

    SELECT foofunc(1,'2011-01-01','2011-01-01', VARIADIC ARRAY[1,2,3,4]);
    

    ...或数组文本字面量形式:

    SELECT foofunc(1,'2011-01-01','2011-01-01', VARIADIC '{1,2,3,4}'::int[]);
    

    后两种形式适用于空数组。

    【讨论】:

    • 我想我可以简单地将函数签名更改为 CREATE OR REPLACE FUNCTION foofunc(int, date, date, VARIADIC ARRAY[]::integer[]) ?并用一个空列表的包装器重载函数(我认为这就是你所说的)。现在,关于传递一个 id 列表,我如何将一个 id 列表传递给 foofunc() - 请参阅我问题底部的旁边。
    • @HomunculusReticulli 问题已更新,以进一步明确和清晰。希望能帮助到你。我没有用语法检查把它们弄糊涂,我是在记忆中工作,但我最近在 Pg 中做了一些可变参数函数,所以它应该是正确的。
    • @HomunculusReticulli 该提议签名的后半部分无效;您不能将数组构造函数作为参数类型。省略ARRAY[]::,只接受variable_name VARIADIC integer[]
    【解决方案3】:

    你的意思是SQL Functions with Variable Numbers of Arguments?如果是这样,请使用 VARIADIC。

    【讨论】:

    • @HomunculusReticulli 请注意,VARIADIC 的行为与您在某些语言中可能使用的可变参数不同。特别是零可变参数不被接受。如果要使用零个可变参数进行调用,请使用语法the_varargs_function(fixedarg1, fixedarg2, VARIADIC ARRAY[]::argtype[]),其中argtype[] 是可变参数数组参数的类型。编写一个提供零参数形式的简单 LANGUAGE SQL 包装函数通常很方便。
    • 不确定 VARIADIC 是否适用于所有场景。它唯一可能(或可能不)包含 id 列表的最后一个参数。之前的参数param1, param2 等将始终存在。
    • @CraigRinger:是的,这听起来更像是我想走的路。您能否充实您的评论作为答案(最好使用一点 SQL 代码),以便我可以从中学习?谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多