Conflito de nomenclatura entre o parâmetro de função e o resultado de JOIN com a cláusula USING

16

Dada esta configuração no Postgres 9.4 atual ( desta pergunta relacionada ):

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

Há também um SQL Fiddle da pergunta anterior.

Eu escrevi a SELECTcom a FULL JOINpara atingir o objetivo da pergunta referenciada. Simplificado:

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

De acordo com as especificações, a maneira correta de abordar a coluna tsé sem qualificação da tabela. Qualquer um dos valores de entrada ( f.tsou b.ts) pode ser NULL. A USINGcláusula cria um caso um tanto estranho: a introdução de uma coluna "input" que não está realmente presente na entrada. Até agora, tão elegante.

Coloquei isso em uma função plpgsql. Por conveniência (ou requisitos), quero os mesmos nomes de coluna para o resultado da função de tabela. Portanto, temos que evitar conflitos de nomeação entre nomes de colunas idênticos e parâmetros de função. Deve ser evitado escolhendo nomes diferentes, mas aqui estamos:

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;

Negrito ênfase para destacar o problema . Não posso usar tssem a qualificação da tabela como antes, porque o plpgsql geraria uma exceção (não estritamente necessária, mas provavelmente útil na maioria dos casos):

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.

Eu sei que posso usar nomes diferentes ou uma subconsulta ou usar outra função. Mas eu me pergunto se existe uma maneira de fazer referência à coluna. Não posso usar a qualificação de tabela. Alguém poderia pensar que deveria haver um caminho.
Existe?

Erwin Brandstetter
fonte

Respostas:

18

De acordo com os documentos PL / pgSQL Under the Hood , você pode usar o parâmetro de configuração plpgsql.variable_conflict, antes de criar a função ou no início da definição da função, declarando como deseja que esses conflitos sejam resolvidos (os 3 valores possíveis são error(o padrão ) use_variablee 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ᵀᴹ
fonte
11
Perfeito. Eu tive a sensação incômoda de que estava perdendo alguma coisa. Lembro-me de ter usado isso no passado. Obrigado!
Erwin Brandstetter