PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

La fonction Postgres crée mais ne s'exécute pas

J'ai eu une situation similaire - fonction avec une large liste de paramètres. Avec les soi-disant paramètres nommés , vous n'avez pas besoin de respecter un ordre de paramètres. Le code est plus long, mais (je l'espère) plus lisible et plus robuste.

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$

Cette fonction peut être appelée avec des paramètres nommés notation :

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

Attention :Lorsque j'utilise un mauvais type - Postgres signale le message :

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.

Le message est valide, mais il n'est pas propre. Il s'agit d'un coût de prise en charge de la surcharge des fonctions. Il existe une autre astuce, comment diviser une longue liste de paramètres et comment trouver ces problèmes plus confortablement.

Postgres prend en charge les types personnalisés. Vous pouvez l'utiliser :

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

vous pouvez écrire une fonction constructeur :

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$

La création de ce système nécessite du travail et n'est pratique que pour les systèmes à longue durée de vie. D'autre part, cela réduit le coût des travaux d'entretien futurs.

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$

Maintenant, plus de notations (combinaison de notations) sont possibles :

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

(1 row)

Les constructeurs aident à la localisation des erreurs :

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.