Namenskonflikt zwischen Funktionsparameter und Ergebnis von JOIN mit USING-Klausel

16

Angesichts dieses Setups in aktuellem Postgres 9.4 ( aus dieser verwandten Frage ):

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');

Es gibt auch eine SQL-Geige aus der vorherigen Frage.

Ich habe ein SELECTmit a geschrieben FULL JOIN, um das Ziel der genannten Frage zu erreichen. Vereinfacht:

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

Die korrekte Adressierung der Spalte tserfolgt gemäß Spezifikation ohne Tabellenqualifizierung. Jeder der Eingabewerte ( f.tsoder b.ts) kann NULL sein. Die USINGKlausel erzeugt einen seltsamen Fall: Eine "Eingabe" -Spalte wird eingefügt, die in der Eingabe nicht vorhanden ist. So weit so elegant.

Ich habe dies in eine plpgsql-Funktion eingefügt. Der Einfachheit halber (oder den Anforderungen halber) möchte ich die gleichen Spaltennamen für das Ergebnis der Tabellenfunktion. Wir müssen also Namenskonflikte zwischen identischen Spaltennamen und Funktionsparametern vermeiden. Sollte am besten vermieden werden, indem man verschiedene Namen auswählt, aber hier sind wir:

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;

Fettdruck, um das Problem hervorzuheben . tsOhne Tabellenqualifizierung kann ich nicht wie zuvor verwenden, da plpgsql eine Ausnahme auslösen würde (nicht unbedingt erforderlich, aber wahrscheinlich in den meisten Fällen nützlich):

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.

Ich weiß, dass ich verschiedene Namen oder eine Unterabfrage verwenden oder eine andere Funktion verwenden kann. Aber ich frage mich, ob es eine Möglichkeit gibt, die Spalte zu referenzieren. Ich kann keine Tabellenqualifikation verwenden. Man würde denken, es sollte einen Weg geben.
Gibt es?

Erwin Brandstetter
quelle

Antworten:

18

Gemäß der Dokumentation PL / pgSQL Under the Hood können Sie den Konfigurationsparameter plpgsql.variable_conflictentweder vor dem Erstellen der Funktion oder zu Beginn der Funktionsdefinition verwenden und angeben, wie solche Konflikte gelöst werden sollen (die drei möglichen Werte sind error(der Standardwert) ) use_variableund 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;
ypercubeᵀᴹ
quelle
1
Perfekt. Ich hatte das quälende Gefühl, etwas zu vermissen. Ich erinnere mich tatsächlich, dass ich das in der Vergangenheit benutzt habe. Vielen Dank!
Erwin Brandstetter