web-dev-qa-db-ja.com

関数からsetofレコード(仮想テーブル)を返す

カスタムコンテンツを含む仮想テーブル(Oracleなど)を返すには、Postgres関数が必要です。テーブルには3つの列と不明な行数があります。

インターネット上で正しい構文が見つかりませんでした。

これを想像してください:

CREATE OR REPLACE FUNCTION "public"."storeopeninghours_tostring" (numeric)
  RETURNS setof record AS
DECLARE
  open_id ALIAS FOR $1;
  returnrecords setof record;
BEGIN
  insert into returnrecords('1', '2', '3');
  insert into returnrecords('3', '4', '5');
  insert into returnrecords('3', '4', '5');
  RETURN returnrecords;
END;

これはどのように正しく書かれていますか?

37
David

(これはすべてpostgresql 8.3.7でテストされています-以前のバージョンはありますか?「$ 1のエイリアス」の使用を見てください)

CREATE OR REPLACE FUNCTION storeopeninghours_tostring(numeric)
 RETURNS SETOF RECORD AS $$
DECLARE
 open_id ALIAS FOR $1;
 result RECORD;
BEGIN
 RETURN QUERY SELECT '1', '2', '3';
 RETURN QUERY SELECT '3', '4', '5';
 RETURN QUERY SELECT '3', '4', '5';
END
$$;

(クエリ結果の代わりに)返すレコードまたは行変数がある場合は、「RETURN QUERY」ではなく「RETURN NEXT」を使用します。

関数を呼び出すには、次のようなことをする必要があります。

select * from storeopeninghours_tostring(1) f(a text, b text, c text);

そのため、関数の出力行スキーマがクエリに含まれることを定義する必要があります。これを避けるために、関数定義で出力変数を指定できます。

CREATE OR REPLACE FUNCTION storeopeninghours_tostring(open_id numeric, a OUT text, b OUT text, c OUT text)
 RETURNS SETOF RECORD LANGUAGE 'plpgsql' STABLE STRICT AS $$
BEGIN
 RETURN QUERY SELECT '1'::text, '2'::text, '3'::text;
 RETURN QUERY SELECT '3'::text, '4'::text, '5'::text;
 RETURN QUERY SELECT '3'::text, '4'::text, '5'::text;
END
$$;

(余分な:: textキャストが必要な理由はよくわかりません...「1」はデフォルトでvarcharです?)

37
araqnid

以前の既存の回答はすべて時代遅れであるか、最初は非効率的でした。

3つのinteger列を返したいと仮定します。

PL/pgSQL関数

最新のPL/pgSQL(PostgreSQL 8.4以降)でこれを行う方法は次のとおりです。

CREATE OR REPLACE FUNCTION f_foo() -- (open_id numeric) -- parameter not used
  RETURNS TABLE (a int, b int, c int) AS
$func$
BEGIN
RETURN QUERY VALUES
  (1,2,3)
, (3,4,5)
, (3,4,5)
;
END
$func$  LANGUAGE plpgsql IMMUTABLE ROWS 3;

Postgres 9.6以降では、 PARALLEL SAFE

コール:

SELECT * FROM f_foo();

主なポイント

  • つかいます - RETURNS TABLE は、返すアドホック行タイプを定義します。
    またはRETURNS SETOF mytbl事前定義された行タイプを使用します。

  • つかいます - RETURN QUERY は、1つのコマンドで複数の行を返します。

  • VALUES 式を使用して、複数の行を手動で入力します。これは標準のSQLであり、これまでずっとでした

  • パラメータが実際に必要な場合、パラメータ名(open_id numeric)の代わりに ALIAS、推奨されません 。この例では、パラメーターは使用されず、ノイズのみが...

  • 完全に正当な識別子を二重引用符で囲む必要はありません。二重引用符は、それ以外の場合は違法な名前(大文字と小文字の混在、違法な文字または予約語)を強制するためにのみ必要です。

  • 関数のボラティリティはIMMUTABLEにすることができます 、結果は変わらないため。

  • ROWS 3はオプションですが、返される行の数はknowなので、Postgresに宣言することもできます。クエリプランナーが最適なプランを選択するのに役立ちます。

シンプルなSQL

このような単純なケースでは、代わりにプレーンなSQLステートメントを使用できます。

VALUES (1,2,3), (3,4,5), (3,4,5)

または、特定の列名とタイプを定義する(または持っている)場合:

SELECT *
FROM  (
   VALUES (1::int, 2::int, 3::int)
        , (3, 4, 5)
        , (3, 4, 5)
   ) AS t(a, b, c);

SQL関数

代わりに、単純な SQL関数 にラップできます。

CREATE OR REPLACE FUNCTION f_foo()
   RETURNS TABLE (a int, b int, c int) AS
$func$
   VALUES (1, 2, 3)
        , (3, 4, 5)
        , (3, 4, 5);
$func$  LANGUAGE sql IMMUTABLE ROWS 3;
37

私は自分の関数で一時テーブルをかなり使います。データベースに戻り値の型を作成してから、その型の変数を作成して返す必要があります。以下は、まさにそれを行うサンプルコードです。

CREATE TYPE storeopeninghours_tostring_rs AS
(colone text,
 coltwo text,
 colthree text
);

CREATE OR REPLACE FUNCTION "public"."storeopeninghours_tostring" () RETURNS setof storeopeninghours_tostring_rs AS
$BODY$
DECLARE
  returnrec storeopeninghours_tostring_rs;
BEGIN
    BEGIN 
        CREATE TEMPORARY TABLE tmpopeninghours (
            colone text,
            coltwo text,
            colthree text
        );
    EXCEPTION WHEN OTHERS THEN
        TRUNCATE TABLE tmpopeninghours; -- TRUNCATE if the table already exists within the session.
    END;
    insert into tmpopeninghours VALUES ('1', '2', '3');
    insert into tmpopeninghours VALUES ('3', '4', '5');
    insert into tmpopeninghours VALUES ('3', '4', '5');

    FOR returnrec IN SELECT * FROM tmpopeninghours LOOP
        RETURN NEXT returnrec;
    END LOOP;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;


select * from storeopeninghours_tostring()
23
Imraan Parker

一時テーブルを作成し、戻り値としてレコードをダンプすることに相当するMSSQLを探してここに上陸した人に... PostgreSQLには存在しません:(-戻り値の型を定義する必要があります。2つの方法があります。これは、関数の作成時またはクエリの作成時に。

こちらをご覧ください: http://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions

8
Brad Holbrook
CREATE OR REPLACE FUNCTION foo(open_id numeric, OUT p1 varchar, OUT p2 varchar, OUT p3 varchar) RETURNS SETOF RECORD AS $$
BEGIN
  p1 := '1'; p2 := '2'; p3 := '3';
  RETURN NEXT; 
  p1 := '3'; p2 := '4'; p3 := '5';
  RETURN NEXT; 
  p1 := '3'; p2 := '4'; p3 := '5';
  RETURN NEXT; 
  RETURN;
END;
$$ LANGUAGE plpgsql;
7
Pavel Stehule