現在の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 もあります。
参照されている質問の目的を達成するために、SELECT
をFULL 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;
問題を強調するための太字の強調。使えない 以前のようにテーブル修飾がない場合、plpgsqlは例外を発生させます(厳密には必要ではありませんが、ほとんどの場合はおそらく有用です)。ts
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.
別の名前やサブクエリを使用したり、別の関数を使用したりできることはわかっています。しかし、列を参照する方法はあるのでしょうか。テーブル修飾は使用できません。そこにすべきであると考えるでしょう方法です。
ある?
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;