PostgreSQLを使用すると、最初のレコードのテーブルの列値がレコード変数に格納されます。例:変数をrecordvar
とします
recordvar.columnname
指定された列名の値を与えます。 columname
を変数で定義します。
var := columnname
columnname
の代わりに変数に置き換えた場合、つまりrecordvar.var
、動作していません。
このような状況での進め方を教えてください。以下はサンプルコードです:
CREATE OR REPLACE FUNCTION getrowdata(id numeric, table_name character varying)
RETURNS SETOF void AS
$BODY$
DECLARE
srowdata record;
reqfield character varying;
value numeric;
BEGIN
RAISE NOTICE 'id: %',id;
reqfield:= 'columnname';
EXECUTE 'select * from datas.'||table_name||' WHERE id = '||id into srowdata;
RAISE NOTICE 'srowdata: %',srowdata;
RAISE NOTICE 'srowdatadata.columnname: %',srowdata.columnname;
value:= srowdata.reqfield;
RAISE NOTICE 'value: %',value;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;
このダミーテーブルの操作
_CREATE TEMP TABLE foo (id int, my_num numeric);
INSERT INTO foo VALUES (1, 12.34)
_
まず、私はあなたの例を単純化して消毒しました:
質問に関係のないいくつかのノイズを削除しました。
_RETURNS SETOF void
_はほとんど意味がありません。代わりに_RETURNS void
_を使用します。
簡単にするために、_character varying
_の代わりにtext
を使用します。
動的SQLを使用する場合、SQLインジェクションから保護するためにhaveがあります。この場合、format()
と_%I
_を使用します。 他の方法があります 。
基本的な問題は、SQLは型と識別子に関して非常に厳格であるということです。 動的テーブル名と、レコードの動的フィールド名-元の例では、anonymousrecordです。 Pl/pgSQLは、これに対処するための十分な機能を備えていません。 Postgresは、匿名レコードの内部が何であるかを知りません。レコードを既知のタイプに割り当てた後でのみ、個々のフィールドを参照できます。
動的な名前のレコードのフィールドを設定しようとする、密接に関連する質問があります。
動的SQLを使用して複合変数フィールドの値を設定する方法
_CREATE OR REPLACE FUNCTION getrowdata1(table_name text, id int)
RETURNS void AS
$func$
DECLARE
srowdata record;
reqfield text := 'my_num'; -- assigning at declaration time for convenience
value numeric;
BEGIN
RAISE NOTICE 'id: %', id;
EXECUTE format('SELECT * FROM %I WHERE id = $1', table_name)
USING id
INTO srowdata;
RAISE NOTICE 'srowdata: %', srowdata;
RAISE NOTICE 'srowdatadata.my_num: %', srowdata.my_num;
/* This does not work, even with dynamic SQL
EXECUTE format('SELECT ($1).%I', reqfield)
USING srowdata
INTO value;
RAISE NOTICE 'value: %', value;
*/
END
$func$ LANGUAGE plpgsql;
_
コール:
_SELECT * from getrowdata1('foo', 1);
_
コメントされた部分は例外を発生させます:
レコードデータ型の列「my_num」を識別できませんでした:SELECT * from getrowdata(1、 'foo')
hstore
このために、追加のモジュール hstore をインストールする必要があります。データベースごとに1回:
_CREATE EXTENSION hstore;
_
それからすべてはこのように働くことができます:
_CREATE OR REPLACE FUNCTION getrowdata2(table_name text, id int)
RETURNS void AS
$func$
DECLARE
hstoredata hstore;
reqfield text := 'my_num';
value numeric;
BEGIN
RAISE NOTICE 'id: %', id;
EXECUTE format('SELECT hstore(t) FROM %I t WHERE id = $1', table_name)
USING id
INTO hstoredata;
RAISE NOTICE 'hstoredata: %', hstoredata;
RAISE NOTICE 'hstoredata.my_num: %', hstoredata -> 'my_num';
value := hstoredata -> reqfield;
RAISE NOTICE 'value: %', value;
END
$func$ LANGUAGE plpgsql;
_
コール:
_SELECT * from getrowdata2('foo', 1);
_
追加のモジュールをインストールせずに代替。
レコード変数に行全体を選択するため、定義ごとに明確に定義されたタイプがあります。これを使って。キーワードは polymorphic types です。
_CREATE OR REPLACE FUNCTION getrowdata3(_tbl anyelement, id int)
RETURNS void AS
$func$
DECLARE
reqfield text := 'my_num';
value numeric;
BEGIN
RAISE NOTICE 'id: %', id;
EXECUTE format('SELECT * FROM %s WHERE id = $1', pg_typeof(_tbl))
USING id
INTO _tbl;
RAISE NOTICE '_tbl: %', _tbl;
RAISE NOTICE '_tbl.my_num: %', _tbl.my_num;
EXECUTE 'SELECT ($1).' || reqfield -- requfield must be SQLi-safe or escape
USING _tbl
INTO value;
RAISE NOTICE 'value: %', value;
END
$func$ LANGUAGE plpgsql;
_
コール:
_SELECT * from getrowdata3(NULL::foo, 1);
_
ここでは3つの目的で入力パラメーター__tbl
_を(ab-)使用します。
この関連する回答(最後の章)の詳細な説明:
さまざまなSELECTクエリの出力を返すようにPL/pgSQL関数をリファクタリングする