具有可变数量输入参数的函数

时间:2013-05-28 00:27:54

标签: sql function postgresql stored-procedures sql-update

我正在PostgreSQL DB中创建一个存储过程(函数),它根据输入更新表。为了创建一个可变数量的参数函数,我正在创建一个名为mode的额外输入参数,我用它来控制我在更新查询中使用的参数。

CREATE OR REPLACE FUNCTION update_site(
    mode integer,
    name character varying,
    city character varying,
    telephone integer,
)
RETURNS integer AS
$$
BEGIN
IF mode = 0 THEN
BEGIN
    UPDATE "Sites" SET 
    ("City","Telephone") = (city,telephone)
    WHERE "SiteName" = name;
    RETURN 1;
    EXCEPTION WHEN others THEN
    RAISE NOTICE 'Error on site update: %, %',SQLERRM,SQLSTATE;
    RETURN 0;
END;
ELSIF mode = 1 THEN
BEGIN
    UPDATE "Sites" SET "City" = city
    WHERE "SiteName" = name;
    RETURN 1;
    EXCEPTION WHEN others THEN
    RAISE NOTICE 'Error on site update: %, %',SQLERRM,SQLSTATE;
    RETURN 0;
END;
    ELSIF mode = 2 THEN
BEGIN
    UPDATE "Sites" SET "Telephone" = telephone
    WHERE "SiteName" = name;
    RETURN 1;
    EXCEPTION WHEN others THEN
    RAISE NOTICE 'Error on site update: %, %',SQLERRM,SQLSTATE;
    RETURN 0;
END;
    ELSE
            RAISE NOTICE 'Error on site update: %, %',SQLERRM,SQLSTATE;
    RETURN 0;
    END IF;
END;
$$ LANGUAGE plpgsql;

什么是最好的?要创建函数update_site(<all the columns of table>)和单独的函数update_site(id integer, <varchar column to update>),还是在一个函数中使用模式来定义差异?哪个选项更有效?一个独特的功能或不同的功能用于各种目的?

2 个答案:

答案 0 :(得分:9)

VARIADIC甚至polymorphic input types和动态SQL等高级功能非常强大。本答案的最后一章提供了一个高级示例:

但对于像您这样的简单案例,您可以使用默认值作为函数参数。这完全取决于具体要求 如果,相关列都已定义NOT NULL,这可能会更简单,更快:

CREATE OR REPLACE FUNCTION update_site(
     _name      text             -- always required, so no default
   , _city      text DEFAULT NULL
   , _telephone integer DEFAULT NULL)
  RETURNS integer AS
$func$
BEGIN
   IF  _city IS NULL
   AND _telephone IS NULL THEN
      RAISE WARNING 'At least one value to update required!';
      RETURN;  -- nothing to update
   END IF;

   UPDATE "Sites"
   SET    "City"      = COALESCE(_city, "City")
        , "Telephone" = COALESCE(_telephone, "Telephone")
   WHERE  "SiteName" = _name;
END
$func$  LANGUAGE plpgsql;

请务必阅读default values in the manual

为了避免参数和列名之间的命名冲突,我习惯在输入参数前加_。这是品味和风格的问题。

  • 第一个参数name没有默认值,因为它始终是必需的。
  • 其他参数可以省略。
  • 至少需要一个,或者WARNING被引发,没有其他事情发生。
  • UPDATE只会更改给定参数的列。
  • 可以轻松扩展 N 参数。

函数调用

对于 Postgres 9.5 或更新版本:

简单的方法是使用positional notation参数。这只允许省略最右边的参数:

SELECT update_site('foo', 'New York');  -- no telephone

Named notation允许省略任何具有默认值的参数:

SELECT update_site(name => 'foo', _telephone => 123);  -- no city

两者都可以合并到mixed notation

SELECT update_site('foo', _telephone => 123);  -- still no city

Postgres 9.4 之前, := 在通话中用于分配:

SELECT update_site(name := 'foo', _telephone := 123);
SELECT update_site('foo', _telephone := 123);

在Postgres 11中仍然有效,以实现向后兼容,但不要在当前版本中使用它。

答案 1 :(得分:3)

您需要了解一些事项:

  • 使用format函数及其%I%L说明符动态构建SQL,然后使用EXECUTE ... USING执行它;以及

  • 使用VARIADIC参数为函数提供可变数量的参数,但需要注意的是它们必须都是相同的数据类型。