Functions with variable number of input parameters

Advanced features like VARIADIC or even polymorphic input types and dynamic SQL are very powerful. The last chapter in this answer provides an advanced example:

For a simple case like yours, you can just use default values for function parameters. It all depends on exact requirements.
If the columns in question are all defined NOT NULL, this would probably be simpler and faster:

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

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

Read about default values in the manual!

To avoid naming conflicts between parameters and column names I make it a habit to prefix input parameters with _. That’s a matter of taste and style.

  • The first parameter name has no default, since it is required at all times.
  • Other parameters can be omitted.
  • At least one is required, or a WARNING is raised and nothing else happens.
  • The UPDATE will only change columns for given parameters.
  • Can easily be expanded for N parameters.

Function call

Three options:

  1. Positional notation
    Is the simple way, but it only allows to omit the rightmost parameter(s):

    SELECT update_site('foo', 'New York');  -- no telephone
    
  2. Named notation
    Allows to omit any parameter that has a default value:

    SELECT update_site(name => 'foo', _telephone => 123);  -- no city
    
  3. Mixed notation
    Combines both:

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

Up to Postgres 9.4, := was used instead of => for assignment in the call:

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

Still valid in Postgres 15 for backward compatibility, but rather use modern syntax.

Leave a Comment