Conflit de nommage entre le paramètre de fonction et le résultat de JOIN avec la clause USING


17

Compte tenu de cette configuration dans Postgres 9.4 actuel (à 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 SELECTavec un FULL JOINpour 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 manière correcte de traiter la colonne tsest sans qualification de table. L'une ou l'autre des valeurs d' entrée ( f.tsou b.ts) peut être NULL. La USINGclause crée 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 mets cela dans une fonction plpgsql. Pour plus de commodité (ou d'exigences), je veux les mêmes noms de colonne pour le résultat de la fonction de table. Nous devons donc éviter les conflits de noms entre les noms de colonnes identiques et les paramètres de fonction. Il vaut mieux éviter de choisir des noms différents, mais nous voici:

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;

Accent audacieux pour souligner le problème . Je ne peux pas utiliser tssans qualification de table comme avant, car plpgsql déclencherait 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 existe un moyen de référencer la colonne. Je ne peux pas utiliser la qualification de table. On pourrait penser qu'il devrait y avoir un moyen.
Y a-t-il?

Réponses:


19

Selon les documents PL / pgSQL Under the Hood , vous pouvez utiliser le paramètre de configuration plpgsql.variable_conflict, soit avant de créer la fonction, soit au début de la définition de la fonction, en déclarant comment vous voulez que ces conflits soient résolus (les 3 valeurs possibles sont error(la valeur par défaut ) use_variableet 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;

1
Parfait. J'ai eu la sensation tenace que je manquais quelque chose. Je me souviens en fait d'avoir utilisé cela dans le passé. Je vous remercie!
Erwin Brandstetter
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.