PREPARE
の秘訣 CREATE FUNCTION
のような*テキスト文字列*(値)を受け取らないため、機能しません しますが、有効なステートメント (コード)。
データを変換するには 実行可能コードに 動的SQL、つまりEXECUTE
を使用する必要があります plpgsql関数またはDO
声明。戻り値の型が最初の関数myresult()
の結果に依存しない限り、これは問題なく機能します。 。そうでなければ、私の前の答えで概説したように、22をキャッチするために戻ってきました:
- postgresでストアドプロシージャの文字列結果を実行する方法
重要な部分は、返品タイプを宣言することです。 (この場合は行タイプ)どういうわけか。 TABLE
を作成できます 、TEMP TABLE
またはTYPE
目的のために。または、プリペアドステートメントまたはリフカーサーを使用できます。
プリペアドステートメントによる解決策
あなたはとても親密でした。パズルの欠けている部分は、生成されたクエリを動的SQLで準備することです。 。
ステートメントを動的に準備する関数
この関数を一度作成します 。これは、関数の最適化された安全なバージョンですmyresult()
:
CREATE OR REPLACE FUNCTION f_prep_query (_tbl regclass, _prefix text)
RETURNS void AS
$func$
BEGIN
IF EXISTS (SELECT 1 FROM pg_prepared_statements WHERE name = 'stmt_dyn') THEN
DEALLOCATE stmt_dyn;
END IF; -- you my or may not need this safety check
EXECUTE (
SELECT 'PREPARE stmt_dyn AS SELECT '
|| string_agg(quote_ident(attname), ',' ORDER BY attname)
|| ' FROM ' || _tbl
FROM pg_catalog.pg_attribute
WHERE attrelid = _tbl
AND attname LIKE _prefix || '%'
AND attnum > 0
AND NOT attisdropped
);
END
$func$ LANGUAGE plpgsql;
regclass
を使用しています テーブル名パラメータ_tbl
の場合 SQLiに対して明確かつ安全にするため。詳細:
- PostgreSQL関数パラメータとしてのテーブル名
情報スキーマにはシステムカタログのoid列が含まれていないため、pg_catalog.pg_attribute
に切り替えました。 information_schema.columns
の代わりに 。それも速いです。これには賛否両論があります:
- 特定のスキーマにテーブルが存在するかどうかを確認する方法
stmt_dyn
という名前のプリペアドステートメントの場合 すでに存在している、PREPARE
例外が発生します。それが許容できる場合は、システムビューのチェックを削除しますpg_prepared_statements
および次のDEALLOCATE
。
より高度なアルゴリズムを使用して、セッションごとに複数のプリペアドステートメントを管理したり、プリペアドステートメントの名前を追加のパラメータとして使用したり、クエリ文字列のMD5ハッシュを名前として使用したりすることもできますが、それだけではありません。この質問の範囲。
PREPARE
に注意してください トランザクションの範囲外で動作します 、一度PREPARE
成功すると、準備されたステートメントはセッションの存続期間中存在します。ラッピングトランザクションが中止された場合は、PREPARE
影響を受けません。 ROLLBACK
できません 準備されたステートメントを削除します。
動的クエリ実行
2つ クエリですが、1つのみ サーバーを呼び出します。そして非常に効率的です。
SELECT f_prep_query('tbl'::regclass, 'pre'::text);
EXECUTE stmt_dyn;
一時テーブルまたはカーソルを作成し、そこから選択/フェッチするよりも、最も単純なユースケースの方が簡単ではるかに効率的です(他のオプションになります)。
SQLフィドル。