私はRETURNS SETOF ct_custom_type
と内部で行うストアドプロシージャを持っています
RETURN QUERY EXECUTE 'some dynamic query'
そして、私はこれをしたいです:この '動的クエリ'が> = 10行を返す場合、それらを返しますが、それが10行未満しか返さない場合、何も返しません(ct_custom_type
の空のセット)。
私は試した:
RETURN QUERY EXECUTE 'some dynamic query'
GET DIAGNOSTICS variable = ROW_COUNT;
IF variable < 10 THEN
# I don't know what to do here or how to accomplish this
END IF;
IF
ブロックでRETURN QUERY SELECT 0, 0, ''::text;
を実行すると(ct_custom_type
は(integer, integer, text)
の複合型であるため、前のクエリ結果にこの「空の行」を追加するだけですが、この場合は何も返しません。 RETURN;
を実行できますが、以前の結果が返されるので、破棄したいと思います。
私はそれを次のように持っています:
EXECUTE 'dynamic query';
GET DIAGNOSTICS variable = ROW_COUNT;
IF variable >= 10 THEN
RETURN QUERY EXECUTE 'dynamic query';
END IF;
動作しますが、このクエリを2回実行したくありませんでした。
次の行に沿って何かを行うことができます。
test=> CREATE OR REPLACE FUNCTION temptabl(cnt integer)
RETURNS SETOF integer AS
$body$
BEGIN
CREATE TEMPORARY TABLE tmp_container ON COMMIT DROP AS
SELECT a
FROM generate_series(1, cnt) t(a);
IF (SELECT count(1) FROM tmp_container) > 5
THEN
RETURN QUERY SELECT a FROM tmp_container;
END IF;
END;
$body$
LANGUAGE plpgsql;
test=> SELECT * FROM temptabl(4);
temptabl
----------
(0 rows)
test=> SELECT * FROM temptabl(6);
temptabl
----------
1
2
3
4
5
6
(6 rows)
この方法では、元のクエリを1回だけ実行する必要があります。他のすべてのステートメントは一時テーブルで機能します。
_
RETURN NEXT
_と_RETURN QUERY
_は、実際には関数から返されません。関数の結果セットに0個以上の行を追加するだけです。その後、実行はPL/pgSQL関数の次のステートメントから続行されます。連続する_RETURN NEXT
_または_RETURN QUERY
_コマンドが実行されると、結果セットが作成されます。引数なしの最後のRETURN
は、制御を関数から終了させます(または、制御を関数の最後に到達させることができます)。
EXCEPTION
を調達そのため、EXCEPTION
を発生させることで操作をキャンセルでき、クライアントは行を取得しません。
それより安くはなりません:
_CREATE OR REPLACE FUNCTION f_min_records(min_ct integer = 10) -- default minimum 10
RETURNS SETOF tbl AS
$func$
DECLARE
row_ct int;
BEGIN
RETURN QUERY EXECUTE 'some dynamic query (matching return type)';
GET DIAGNOSTICS row_ct = ROW_COUNT;
IF row_ct < min_ct THEN
RAISE EXCEPTION 'Only % rows! Requested minimum was %.', row_ct, min_ct;
END IF;
END
$func$ LANGUAGE plpgsql;
_
呼び出し(デフォルトで最小10行):
_SELECT * FROM f_min_records_wrapper();
_
マニュアルに コード例(get_available_flightid()
) を含めました。
EXCEPTION
を調達しないでください私の知る限り、戻り値セットが実際に返されないようにする唯一の方法は、例外を発生させることです。例外を発生させたくない場合は、現在のplpgsqlを少し使っているだけです。
同じ関数で EXCEPTION
をトラップしても、結果セットは引き続き返されます。
ネストされたブロック で解決しようとしましたが失敗しました。戻り値セットに違いはないようです。
しかし、関数呼び出しを外部関数にネストして、そこで例外をキャッチできます。それは期待通りに機能します:
上記の拡張機能に加えて:
_CREATE OR REPLACE FUNCTION f_min_records(min_ct integer = 10) -- default minimum 10
RETURNS SETOF t AS
$func$
DECLARE
row_ct int;
BEGIN
RETURN QUERY EXECUTE 'SELECT * from t'; -- some dynamic query (matching return type)
GET DIAGNOSTICS row_ct = ROW_COUNT;
IF row_ct < min_ct THEN
RAISE SQLSTATE 'BRRRR' -- 5 ASCII chars
USING MESSAGE = format('Only %s rows! Requested minimum was %s.', row_ct, min_ct);
END IF;
END
$func$ LANGUAGE plpgsql;
_
実際に呼び出すラッパー関数を作成します。
_CREATE OR REPLACE FUNCTION f_min_records_wrapper(min_ct integer = 10)
RETURNS SETOF t AS
$func$
BEGIN
RETURN QUERY
SELECT * from f_min_records(min_ct);
EXCEPTION
WHEN SQLSTATE 'BRRRR' THEN
RAISE NOTICE '%', SQLERRM; -- optionally pass error msg
END
$func$ LANGUAGE plpgsql;
_
コール:
_SELECT * FROM f_min_records_wrapper(17);
_
deszoの答え と同じ基本的な考え方ですが、個別のカウントとその他の機能は避けてください。
_CREATE OR REPLACE FUNCTION f_temptbl(min_ct integer = 10)
RETURNS SETOF t AS
$func$
DECLARE
row_ct int;
BEGIN
DROP TABLE IF EXISTS _temptbl; -- for mult. calls in 1 transaction
CREATE TEMP TABLE _temptbl (LIKE t) ON COMMIT DROP; -- match RETURNS type
EXECUTE 'INSERT INTO _temptbl SELECT * FROM t'; -- text with dyn SQL
GET DIAGNOSTICS row_ct = ROW_COUNT;
IF row_ct >= min_ct THEN
RETURN QUERY TABLE _temptbl;
END IF;
END;
$func$ LANGUAGE plpgsql;
_
リターンセットをキャンセルするコマンドはすばらしいでしょう。
_RETURN CANCEL;
_
または、「ロールバック」するオプションの行数を使用することもできます(デフォルトはすべて):
_RETURN CANCEL 10;
_