同じストアド関数内の別のクエリのレコード型変数に格納されたクエリ結果を使用するにはどうすればよいですか? Postgres 9.4.4を使用します。
このようなテーブルでは:
create table test (id int, tags text[]);
insert into test values (1,'{a,b,c}'),
(2,'{c,d,e}');
私は以下のような関数(簡単な)を書きました:
CREATE OR REPLACE FUNCTION func(_tbl regclass)
RETURNS TABLE (t TEXT[], e TEXT[])
LANGUAGE plpgsql AS $$
DECLARE
t RECORD;
c INT;
BEGIN
EXECUTE format('SELECT id, tags FROM %s', _tbl) INTO t;
SELECT count(*) FROM t INTO c;
RAISE NOTICE '% results', c;
SELECT * FROM t;
END
$$;
...しかし動作しませんでした:
select func('test');
ERROR: 42P01: relation "t" does not exist LINE 1: SELECT count(*) FROM t ^ QUERY: SELECT count(*) FROM t CONTEXT: PL/pgSQL function func(regclass) line 7 at SQL statement LOCATION: parserOpenTable, parse_relation.c:986
コアの誤解:record
変数は、テーブル(よく知られたタイプの0-n行)ではなく、single行(またはNULL)を保持します。 PostgresやPL/pgSQLには「テーブル変数」はありません。タスクに応じて、さまざまな選択肢があります。
したがって、multiple行をrecord
型変数に割り当てることはできません。この声明では:
_EXECUTE format('SELECT id, tags FROM %s', _tbl) INTO t;
_
... Postgresは最初の行のみを割り当て、残りを破棄します。クエリでは「最初の」が適切に定義されていないため、最終的に任意の選択が行われます。明らかに、最初に述べた誤解によるものです。
record
変数は、SQLクエリのテーブルの代わりに使用することもできません。これがエラーの主な原因です。
リレーション "t"は存在しません
t
は単一のレコード/行であるため、count(*)
が最初から意味をなさないことは明らかです。
最後に(残りが機能する場合でも)、戻り値の型が間違っているようです: _。 _(t TEXT[], e TEXT[])
_id, tags
_をt
に選択するので、_(id int, e TEXT[])
_のようなものを返したいでしょう。
あなたがしようとしていることは次のように動作します:
_CREATE OR REPLACE FUNCTION func(_tbl regclass)
RETURNS TABLE (id int, e text[]) AS
$func$
DECLARE
_ct int;
BEGIN
EXECUTE format(
'CREATE TEMP TABLE tmp ON COMMIT DROP AS
SELECT id, tags FROM %s'
, _tbl);
GET DIAGNOSTICS _ct = ROW_COUNT; -- cheaper than another count(*)
-- ANALYZE tmp; -- if you are going to run multiple queries
RAISE NOTICE '% results', _ct;
RETURN QUERY TABLE tmp;
END
$func$ LANGUAGE plpgsql;
_
呼び出し(構文に注意してください!):
_SELECT * FROM func('test');
_
関連:
単なる概念実証。テーブル全体を選択している間は、代わりに基になるテーブルを使用するだけです。実際には、クエリにいくつかのWHERE
句があります...
潜んでいる型の不一致に注意してください、count()
はbigint
を返します。これをinteger
変数に割り当てることはできません。キャストが必要です:count(*)::int
。
しかし、それを完全に置き換えました。EXECUTE
の直後にこれを実行する方が安価です。
_GET DIAGNOSTICS _ct = ROW_COUNT;
_
なぜANALYZE
?
余談:プレーンSQLのCTEが仕事をすることがよくあります