PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Die Postgres-Funktion wird erstellt, aber nicht ausgeführt

Ich hatte eine ähnliche Situation - Funktion mit breiter Parameterliste. Mit sogenannten benannten Parametern , müssen Sie keine Parameterreihenfolge beachten. Der Code ist länger, aber (hoffentlich) lesbarer und robuster.

CREATE TABLE tab(name text, surname text, address text, city text, zip text);

CREATE OR REPLACE FUNCTION public.fx(name text, surname text,
                                     address text, city text, zip text)
RETURNS void
LANGUAGE plpgsql
AS $function$
BEGIN
  INSERT INTO tab(name, surname, address, city, zip)
    VALUES(fx.name, fx.surname, fx.address, fx.city, fx.zip);
  -- ... some other logic
END;
$function$

Diese Funktion kann mit benannten Parametern aufgerufen werden Schreibweise:

SELECT fx(name := 'Pavel', surname := 'Stehule',
          address := 'Skalice 12', city := 'Benesov', zip := '12');

Achtung:Wenn ich einen falschen Typ verwende, meldet Postgres folgende Nachricht:

postgres=#   SELECT fx(name := 'Pavel', surname := 'Stehule',
              address := 'Skalice 12', city := 'Benesov', zip := 12);
ERROR:  function fx(name := unknown, surname := unknown, address := unknown, city := unknown, zip := integer) does not exist
LINE 1: SELECT fx(name := 'Pavel', surname := 'Stehule',
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

Die Nachricht ist gültig, aber sie ist nicht sauber. Es ist ein Preis für die Unterstützung der Funktionsüberladung. Es gibt einen anderen Trick, wie man lange Parameterlisten aufteilt und wie man diese Punkte bequemer findet.

Postgres unterstützt benutzerdefinierte Typen. Sie können es verwenden:

CREATE TYPE person_type AS (name text, surname text);
CREATE TYPE address_type AS (address text, city text, zip text);

Sie können eine Konstruktorfunktion schreiben:

CREATE OR REPLACE FUNCTION public._person_type(name text, surname text)
RETURNS person_type
LANGUAGE plpgsql
AS $function$
DECLARE r person_type;
BEGIN
  r.name = name;
  r.surname = surname;
  RETURN r;
END;
$function$

CREATE OR REPLACE FUNCTION public._address_type(address text, city text, zip text)
RETURNS address_type
LANGUAGE plpgsql
AS $function$ DECLARE r address_type;
BEGIN
  r.address = address;
  r.city = city;
  r.zip = zip;
  RETURN r;
END;
$function$

Das Erstellen dieses Systems erfordert einige Arbeit und ist nur für langlebige Systeme praktisch. Andererseits reduziert es die Kosten für zukünftige Wartungsarbeiten.

CREATE OR REPLACE FUNCTION public.fx(p person_type, a address_type)
RETURNS void
LANGUAGE plpgsql
AS $function$
BEGIN
  INSERT INTO tab(name, surname, address, city, zip)
    VALUES(p.name, p.surname, a.address, a.city, a.zip);
   -- ... some other logic
END;
$function$

Nun sind weitere Notationen (Kombination von Notationen) möglich:

postgres=# SELECT fx(_person_type('Pavel','Stehule'),
postgres(#           _address_type('Skalice 12','Benesov', '25601'));
 fx 
----

(1 row)

Konstruktoren helfen bei der Fehlerlokalisierung:

postgres=# SELECT fx(_person_type('Pavel','Stehule'),
          _address_type('Skalice 12','Benesov', 25601));
ERROR:  function _address_type(unknown, unknown, integer) does not exist
LINE 2:           _address_type('Skalice 12','Benesov', 25601));
                  ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.