19

PostgreSQL を使用して、最初のレコードのテーブルの列の値がレコード変数に格納されます。例: 変数を次のようにします。recordvar

recordvar.columnname

指定された列名の値を返します。columnameを変数で定義します。

var := columnname

代わりcolumnnameに、変数 ie に置き換えると、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;
4

1 に答える 1

24

このダミー テーブルの操作

CREATE TEMP TABLE foo (id int, my_num numeric);
INSERT INTO foo VALUES (1, 12.34)

まず、例を単純化してサニタイズしました。

  • 質問に関係のないノイズを削除しました。

  • RETURNS SETOF voidほとんど意味がありません。RETURNS void代わりに使っています。

  • 簡単にするために、text代わりにを使用します。character varying

  • 動的 SQLを使用する場合、SQL インジェクションから保護する必要があります。この場合はformat()withを使用します。他にも方法があります%I

基本的な問題は、SQL が型と識別子に非常に厳格であることです。動的テーブル名とレコードの動的フィールド名 (元の例では匿名レコード) を操作しています。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);

多形型

追加のモジュールをインストールしない代替。

レコード変数に行全体を選択するため、定義ごとに適切に定義された型があります。これを使って。キーワードは多相型です。

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);

-> SQLfiddle

于 2013-08-10T14:01:21.497 に答える