web-dev-qa-db-ja.com

関数パラメーターとUSING句を使用したJOINの結果の名前の競合

現在の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');

前の質問の SQL Fiddle もあります。

参照されている質問の目的を達成するために、SELECTFULL JOINとともに記述しました。簡略化:

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

仕様に従って、列tsをアドレス指定する正しい方法は、テーブル修飾なしです。 input値(f.tsまたはb.ts)のいずれかをNULLにすることができます。 USING句は少し奇妙なケースを作成します。実際には入力に存在しない「入力」列を導入します。これまでのところエレガント。

これをplpgsql関数に入れました。便宜(または要件)のために、テーブル関数の結果にも同じ列名を使用します。したがって、同一の列名と関数パラメーターの間の名前の競合を回避する必要があります。別の名前を選択することで回避するのが最善ですが、ここでは次のようにします。

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;

問題を強調するための太字の強調。使えない 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.

別の名前やサブクエリを使用したり、別の関数を使用したりできることはわかっています。しかし、列を参照する方法はあるのでしょうか。テーブル修飾は使用できません。そこにすべきであると考えるでしょう方法です。
ある?

17

Docs PL/pgSQL Under the Hood によると、設定パラメータplpgsql.variable_conflict、関数を作成する前、または関数定義の開始時に、そのような競合を解決する方法を宣言します(3つの可能な値はerror(デフォルト)、use_variableおよび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;
19
ypercubeᵀᴹ