41

カスタムコンテンツを含む仮想テーブル(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;

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

4

6 に答える 6

43

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

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 QUERY1つのコマンドで複数の行を返すために使用します。

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

  • 実際にパラメータが必要な場合(open_id numeric)は、の代わりにパラメータ名を使用してください。ALIASこれはお勧めできません。この例では、パラメータは使用されておらず、ノイズだけです...

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

  • IMMUTABLE結果は決して変化しないため、関数のボラティリティはになる可能性があります。

  • ROWS 3はオプションですが、返される行数がわかっているので、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;
于 2013-06-22T03:41:52.670 に答える
42

(これはすべてpostgresql 8.3.7でテストされています-以前のバージョンはありますか?「ALIASFOR $ 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
$$;

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

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

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である可能性がありますか?)

于 2009-06-05T10:50:05.897 に答える
25

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

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()
于 2009-06-05T11:46:05.207 に答える
8
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;
于 2009-06-05T10:59:27.920 に答える
8

一時テーブルを作成し、そのレコードをリターンとしてダンプするのと同等のMSSQLを探している人は、PostgreSQLには存在しません:(-リターンタイプを定義する必要があります。2つの方法があります。これは、関数の作成時またはクエリの作成時です。

ここを参照してください: http ://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions

于 2010-11-30T01:05:48.860 に答える
0

PostgreSQL 11以降、プロシージャを使用できます。

CREATE OR REPLACE PROCEDURE f_foo()  LANGUAGE plpgsql
   AS
$$
BEGIN
drop table if exists foo cascade;
create temp table  IF NOT EXISTS foo (a int, b int, c int);
insert into foo VALUES
  (1,2,3)
, (3,4,5)
, (3,4,5)
;
END
$$;

一時テーブルが必要な場合は、それを呼び出すことができます。

call f_foo();

テーブルfooが存在する場合は、ドロップします。

于 2021-12-07T09:22:42.610 に答える