web-dev-qa-db-fra.com

Nommer le conflit entre le paramètre de fonction et le résultat de la participation à l'utilisation de la clause

Compte tenu de cette configuration dans Postgres actuel 9.4 ( à partir de cette question connexe ):

CREATE TABLE foo (ts, foo) AS 
VALUES (1, 'A')  -- int, text
     , (7, 'B');

CREATE TABLE bar (ts, bar) AS
VALUES (3, 'C')
     , (5, 'D')
     , (9, 'E');

Il y a aussi un SQL FIDDLE de la question précédente.

J'ai écrit un SELECT avec un FULL JOIN Pour atteindre l'objectif de la question référencée. Simplifié:

SELECT ts, f.foo, b.bar
FROM   foo f
FULL   JOIN bar b USING (ts);

Selon les spécifications, la bonne façon d'adresser la colonne ts est sans qualification de table. Soit de entrée valeurs (f.ts ou alors b.ts) peut être nul. La clause USING crée un bit d'un cas étrange: introduire une colonne "entrée" qui n'est pas réellement présente dans l'entrée. Jusqu'à présent si élégant.

Je l'ai mis dans une fonction PLPGSQL. Pour plus de commodité (ou exigences), je veux les mêmes noms de colonne pour le résultat de la fonction Table. Nous devons donc éviter de nommer des conflits entre noms de colonnes identiques et paramètres de fonction. Devrait mieux être évité en cueillant des noms différents, mais nous sommes ici:

CREATE OR REPLACE FUNCTION f_merge_foobar()
  RETURNS TABLE(ts int, foo text, bar text) AS
$func$
BEGIN
   FOR ts, foo, bar IN
      SELECT COALESCE(f.ts, b.ts), f.foo, b.bar
      FROM   foo f
      FULL   JOIN bar b USING (ts)
   LOOP
      -- so something
      RETURN NEXT;
   END LOOP;
END
$func$ LANGUAGE plpgsql;

Soulignez audacieux pour mettre en surbrillance le problème . Je ne peux pas utiliser ts Sans qualification de table comme avant, car la PLPGSQL souleverait une exception (pas strictement nécessaire, mais probablement utile dans la plupart des cas):

ERROR:  column reference "ts" is ambiguous
LINE 1: SELECT ts, f.foo, b.bar
               ^
DETAIL:  It could refer to either a PL/pgSQL variable or a table column.

Je sais que je peux utiliser des noms différents ou une sous-requête ou utiliser une autre fonction. Mais je me demande s'il y a un moyen de faire référence à la colonne. Je ne peux pas utiliser la qualification de table. On y penserait devrait être un moyen.
Y a-t-il?

17
Erwin Brandstetter

Selon les documents PL/PGSQL sous le capot , vous pouvez utiliser le paramètre de configuration plpgsql.variable_conflict, avant de créer la fonction ou du début de la définition de la fonction, déclarant comment vous voulez que ces conflits soient résolus (les 3 valeurs possibles sont error (la valeur par défaut ), use_variable et use_column):

CREATE OR REPLACE FUNCTION pg_temp.f_merge_foobar()
  RETURNS TABLE(ts int, foo text, bar text) AS
$func$
#variable_conflict use_column             -- how to resolve conflicts
BEGIN
   FOR ts, foo, bar IN
      SELECT ts, f.foo, b.bar
      FROM   foo f
      FULL   JOIN bar b USING (ts)
   LOOP
      -- do something
      RETURN NEXT;
   END LOOP;
END
$func$ LANGUAGE plpgsql;
19
ypercubeᵀᴹ