Postgresql

函式參數與使用 USING 子句的 JOIN 結果之間的命名衝突

  • September 23, 2021

鑑於目前 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');

db<>fiddle here(也來自上一個問題)。

我用 a 寫了SELECT一個FULL JOIN來實現引用問題的目標。簡化:

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

根據規範,處理該列的正確方法ts是沒有表限定。任何一個輸入值 (f.tsb.ts) 都可以為 NULL。該USING子句創建了一些奇怪的情況:引入了一個實際上不存在於輸入中的“輸入”列。到目前為止如此優雅。

我把它放在一個 plpgsql 函式中。為了方便(或要求),我希望表函式的結果具有相同的列名。所以我們必須避免相同的列名和函式參數之間的命名衝突。最好通過選擇不同的名稱來避免,但我們在這裡:

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$;

大膽強調突出問題。我不能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.

我知道我可以使用不同的名稱或子查詢或使用其他函式。但我想知道是否有辦法引用該列。我不能使用表限定。人們會認為應該有一種方法。

有沒有?

根據文件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$;

引用自:https://dba.stackexchange.com/questions/105831