31

オプションの引数を使用して PL/pgSQL 関数を作成しようとしています。フィルター処理されたレコードのセット (指定されている場合) に基づいてクエリを実行し、それ以外の場合は、テーブル内のデータ セット全体に対してクエリを実行します。

(疑似コード) :

CREATE OR REPLACE FUNCTION foofunc(param1 integer, param2 date, param2 date, optional_list_of_ids=[]) RETURNS SETOF RECORD AS $$
    IF len(optional_list_of_ids) > 0 THEN
        RETURN QUERY (SELECT * from foobar where f1=param1 AND f2=param2 AND id in optional_list_of_ids);
    ELSE
        RETURN QUERY (SELECT * from foobar where f1=param1 AND f2=param2);
    ENDIF
$$ LANGUAGE SQL;

この機能を実装する正しい方法は何でしょうか?

余談ですが、そのような関数を別の外部関数で呼び出す方法を知りたいです。これは私が行う方法です-それは正しいですか、それともより良い方法がありますか?

CREATE FUNCTION foofuncwrapper(param1 integer, param2 date, param2 date) RETURNS SETOF RECORD AS $$
BEGIN
   CREATE TABLE ids AS SELECT id from foobar where id < 100;
   RETURN QUERY (SELECT * FROM foofunc(param1, param2, ids));
END
$$ LANGUAGE SQL
4

3 に答える 3

47

PostgreSQL 8.4(実行しているようです)以降、関数パラメーターのデフォルト値があります。パラメータを最後に配置してデフォルトを指定する場合は、呼び出しから単純に省略できます。

CREATE OR REPLACE FUNCTION foofunc(_param1 integer
                                 , _param2 date
                                 , _ids    int[] DEFAULT '{}')
  RETURNS SETOF foobar         -- declare return type!
  LANGUAGE plpgsql AS
$func$
BEGIN  -- required for plpgsql
   IF _ids <> '{}'::int[] THEN  -- exclude empty array and NULL
      RETURN QUERY
      SELECT *
      FROM   foobar
      WHERE  f1 = _param1
      AND    f2 = _param2
      AND    id = ANY(_ids);    -- "IN" is not proper syntax for arrays
   ELSE
      RETURN QUERY
      SELECT *
      FROM   foobar
      WHERE  f1 = _param1
      AND    f2 = _param2;
   END IF;
END  -- required for plpgsql
$func$;

主なポイント:

  • キーワードDEFAULTは、パラメーターのデフォルトを宣言するために使用されます。短い代替: =.

  • param1乱雑な例から冗長を削除しました。

  • を返すので、戻り値の型をではなくSELECT * FROM foobarとして宣言します。匿名レコードを使用する後者の形式は非常に扱いにくく、すべての呼び出しで列定義リストを提供する必要があります。RETURNS SETOF foobarRETURNS SETOF record

  • int[]関数パラメーターとして整数 ( ) の配列を使用します。それに応じてIF式とWHERE句を調整しました。

  • IFステートメントはプレーン SQL では使用できません。そのためでなければなりませんLANGUAGE plpgsql

の有無にかかわらず呼び出す_ids:

SELECT * FROM foofunc(1, '2012-1-1'::date);

事実上同じ:

SELECT * FROM foofunc(1, '2012-1-1'::date, '{}'::int[]);

呼び出しが明確であることを確認する必要があります。同じ名前で 2 つのパラメーターを持つ別の関数がある場合、Postgres はどれを選択すればよいか分からない可能性があります。明示的なキャスト (私が示すように) は、それを絞り込みます。それ以外の場合、型指定されていない文字列リテラルも機能しますが、明示的であることは問題ありません。

別の関数内から呼び出す:

CREATE FUNCTION foofuncwrapper(_param1 integer, _param2 date)
  RETURNS SETOF foobar
  LANGUAGE plgpsql AS
$func$
DECLARE
   _ids int[] := '{1,2,3}';
BEGIN
   -- whatever

   RETURN QUERY
   SELECT * FROM foofunc(_param1, _param2, _ids);
END
$func$;
于 2012-07-22T21:41:13.237 に答える
4

このスレッドでのFrankの回答について詳しく説明します。

VARIADIC引数は唯一の引数である必要はなく、最後の引数のみです。

ゼロの可変引数を取る可能性のある関数に使用できますがVARIADIC、ゼロの引数には別の呼び出しスタイルが必要であるという点で少し面倒です。醜さを隠すラッパー関数を提供できます。次のような初期可変関数定義が与えられた場合:

CREATE OR REPLACE FUNCTION foofunc(param1 integer, param2 date, param2 date, optional_list_of_ids VARIADIC integer[]) RETURNS SETOF RECORD AS $$
....
$$ language sql;

引数がゼロの場合は、次のようなラッパーを使用します。

CREATE OR REPLACE FUNCTION foofunc(integer, date, date) RETURNS SETOF RECORD AS $body$
SELECT foofunc($1,$2,$3,VARIADIC ARRAY[]::integer[]);
$body$ LANGUAGE 'sql';

VARIADIC '{}'::integer[]または、直接のように空の配列でメイン関数を呼び出すだけです。ラッパーは醜いですが、醜さを含んでいるので、ラッパーを使用することをお勧めします.

直接呼び出しは可変長形式で行うことができます:

SELECT foofunc(1,'2011-01-01','2011-01-01', 1, 2, 3, 4);

... または配列 ctor を使用した配列呼び出しフォーム:

SELECT foofunc(1,'2011-01-01','2011-01-01', VARIADIC ARRAY[1,2,3,4]);

... または配列テキスト リテラル形式:

SELECT foofunc(1,'2011-01-01','2011-01-01', VARIADIC '{1,2,3,4}'::int[]);

後の 2 つの形式は、空の配列で機能します。

于 2012-07-17T10:58:40.837 に答える
1

可変数の引数を持つ SQL 関数のことですか? その場合は、VARIADIC を使用してください。

于 2012-07-17T10:27:38.440 に答える