関数を使用してクエリからの結果セットを処理する場合、最適なオプションはSELECT ... INTO TEMPORARY TABLE
、一時テーブル名を使用して関数を呼び出すことです。
些細な行セットを生成する方法を考えると、PostgreSQL 関数で行セットを使用するのは厄介なほど困難です。私が知っている唯一の方法は、refcursor を使用するか、一時テーブルを処理するか、集計関数またはウィンドウ関数を実装することです。後者の 2 つのオプションでは、返される行数を制御できないため、目的には適していません。
関数は、関数を呼び出す CTE の共通テーブル式エイリアスを参照できないため、CTE を使用して仮想テーブルを作成し、テーブルの名前を関数に渡すことはできません。動作しないことを示す例:
CREATE OR REPLACE FUNCTION dynsql(tname text, colname text) RETURNS SETOF RECORD AS
$$
BEGIN
RETURN QUERY EXECUTE format('SELECT %I FROM %I', colname, tname);
END;
$$ LANGUAGE plpgsql;
WITH dummy(col) AS (VALUES (1),(2),(3))
SELECT * FROM dynsql('dummy','col') t(id integer);
結果:
ERROR: relation "dummy" does not exist
...式のエイリアスはWITH
式に対してローカルであるためWITH
です。(関数から参照できると便利ですが、そうすると、あらゆる種類の刺激的な名前衝突の問題や、SECURITY DEFINER
関数に関するセキュリティの問題が発生します。)
refcursor を使用する PL/PgSQL 関数を作成することはできますが、これにはDECLARE
クエリを使用してカーソルを作成し、それを関数に渡す必要があります。通常の関数呼び出し構文をそのまま使用することはできません。また、非常に非効率的でありLOOP
、関数に ing が必要です。あまり役に立たないと思います。
関数を実装するときはEXECUTE format(...) USING ...
、動的 SQL をあまりひどくしないようにするために使用します。この以前の回答を参照してください。