Konflikt nazewnictwa między parametrem funkcji a wynikiem JOIN z klauzulą ​​USING

17

Biorąc pod uwagę tę konfigurację w aktualnym Postgres 9.4 ( z tego powiązanego pytania ):

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

Istnieje również SQL Fiddle z poprzedniego pytania.

Napisałem SELECTz, FULL JOINaby osiągnąć cel przywoływanego pytania. Uproszczony:

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

Zgodnie ze specyfikacjami prawidłowym sposobem adresowania kolumny tsjest brak kwalifikacji tabeli. Każda z wartości wejściowych ( f.tslub b.ts) może mieć wartość NULL. USINGKlauzula tworzy trochę dziwnym przypadku: wprowadzenie „Input” kolumnę, która nie jest rzeczywiście obecny na wejściu. Jak dotąd tak elegancko.

Umieściłem to w funkcji plpgsql. Dla wygody (lub wymagań) chcę te same nazwy kolumn dla wyniku funkcji tabeli. Musimy więc unikać konfliktów nazw między identycznymi nazwami kolumn i parametrami funkcji. Najlepiej tego unikać, wybierając różne nazwy, ale oto:

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;

Odważny nacisk na podkreślenie problemu . Nie mogę używać tsbez kwalifikacji tabeli jak poprzednio, ponieważ plpgsql spowodowałby wyjątek (nie jest to absolutnie konieczne, ale prawdopodobnie przydatne w większości przypadków):

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.

Wiem, że mogę używać różnych nazw lub podzapytań lub używać innej funkcji. Ale zastanawiam się, czy istnieje sposób na odniesienie do kolumny. Nie mogę użyć kwalifikacji do stołu. Można by pomyśleć, że powinien istnieć sposób.
Jest tu?

Erwin Brandstetter
źródło

Odpowiedzi:

19

Zgodnie z dokumentacją PL / pgSQL Pod maską możesz użyć parametru konfiguracyjnego plpgsql.variable_conflict, albo przed utworzeniem funkcji, albo na początku definicji funkcji, deklarując, jak chcesz rozwiązać takie konflikty (3 możliwe wartości to error(domyślna ) use_variablei 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ᵀᴹ
źródło
1
Doskonały. Miałem dokuczliwe wrażenie, że czegoś mi brakuje. Właściwie pamiętam, że korzystałem z tego w przeszłości. Dziękuję Ci!
Erwin Brandstetter,