Postgresql

PostgreSQL 儲存過程返回行或空集

  • January 19, 2018

我有一個儲存過程,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 &lt; 10 THEN

   # I don't know what to do here or how to accomplish this

END IF;

如果我RETURN QUERY SELECT 0, 0, ''::text;IF塊中這樣做(因為ct_custom_type是 的複合類型(integer, integer, text),它只是將此“空行”添加到先前的查詢結果中,但在這種情況下我不想返回任何內容,我可以這樣做RETURN;,但它會返回先前的結果,我想丟棄它。

我有這樣的:

EXECUTE 'dynamic query';

GET DIAGNOSTICS variable = ROW_COUNT;
IF variable &gt;= 10 THEN
   RETURN QUERY EXECUTE 'dynamic query';
END IF;

它有效,但我不想兩次執行此查詢。

您可以按照以下方式進行操作:

test=&gt; 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) &gt; 5
   THEN
       RETURN QUERY SELECT a FROM tmp_container;
   END IF;
END;
$body$
LANGUAGE plpgsql;


test=&gt; SELECT * FROM temptabl(4);
temptabl 
----------
(0 rows)

test=&gt; SELECT * FROM temptabl(6);
temptabl 
----------
       1
       2
       3
       4
       5
       6
(6 rows)

這樣,您只需執行一次原始查詢。所有其他語句都在臨時表上工作。

返回集

根據文件:

RETURN NEXT並且RETURN QUERY實際上並不從函式返回——它們只是將零或多行附加到函式的結果集中。然後繼續執行 PL/pgSQL 函式中的下一條語句。隨著連續RETURN NEXTRETURN QUERY命令的執行,結果集被建立起來。finalRETURN應該沒有參數,導致控制退出函式(或者你可以讓控製到達函式的末尾)。

EXCEPTION改為加註

因此,您可以通過引發 an 來取消操作,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 &lt; 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 &lt; 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 &gt;= min_ct THEN
     RETURN QUERY TABLE _temptbl;
  END IF;
END;
$func$  LANGUAGE plpgsql;

SQL Fiddle展示了所有內容。

Feature Wish - 目前不存在(包括9.4)

取消返回集的命令會很棒:

RETURN CANCEL;

或者甚至可以選擇“回滾”的行數(預設為全部):

RETURN CANCEL 10;

引用自:https://dba.stackexchange.com/questions/40214