函数参数和带有 USING 子句的 JOIN 结果之间的命名冲突

Erw*_*ter 18 postgresql join naming-convention parameter plpgsql

鉴于当前 Postgres 9.4 中的此设置(来自此相关问题):

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');
Run Code Online (Sandbox Code Playgroud)

db<> fiddle here(也来自上一个问题)。

SELECT用 a写了一个FULL JOIN来实现引用问题的目标。简化:

SELECT ts, f.foo, b.bar
FROM   foo f
FULL   JOIN bar b USING (ts);
Run Code Online (Sandbox Code Playgroud)

As per specifications, the correct way to address the column ts is without table qualification. Either of the input values (f.ts or b.ts) can be NULL. The USING clause creates a bit of an odd case: introducing an "input" column that's not actually present in the input. So far so elegant.

I put this in a plpgsql function. For convenience (or requirements) I want the same column names for the result of the table function. So we have to avoid naming conflicts between identical column names and function parameters. Should best be avoided by picking different names, but here we are:

CREATE OR REPLACE FUNCTION f_merge_foobar()
  RETURNS TABLE(ts int, foo text, bar text)
  LANGUAGE plpgsql 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$;
Run Code Online (Sandbox Code Playgroud)

大胆强调突出问题。我不能ts像以前一样在没有表限定的情况下使用,因为 plpgsql 会引发异常(不是绝对必要的,但在大多数情况下可能有用):

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.
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用不同的名称或子查询或使用其他函数。但我想知道是否有办法引用该列。我不能使用表格限定。有人会认为应该有一种方法。
在那儿?

ype*_*eᵀᴹ 21

根据文档PL/pgSQL Under the Hood,您可以plpgsql.variable_conflict在创建函数之前或在函数定义开始时使用配置参数,声明您希望如何解决此类冲突。
3 种可能的设置是error(默认)use_variableuse_column

CREATE OR REPLACE FUNCTION f_merge_foobar()
  RETURNS TABLE(ts int, foo text, bar text)
  LANGUAGE plpgsql 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$;
Run Code Online (Sandbox Code Playgroud)