PostgreSQL 儲存過程返回行或空集
我有一個儲存過程,
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;
如果我
RETURN QUERY SELECT 0, 0, ''::text;
在IF
塊中這樣做(因為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;
它有效,但我不想兩次執行此查詢。
您可以按照以下方式進行操作:
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)
這樣,您只需執行一次原始查詢。所有其他語句都在臨時表上工作。
返回集
RETURN NEXT
並且RETURN QUERY
實際上並不從函式返回——它們只是將零或多行附加到函式的結果集中。然後繼續執行 PL/pgSQL 函式中的下一條語句。隨著連續RETURN NEXT
或RETURN 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 < 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;
Feature Wish - 目前不存在(包括9.4)
取消返回集的命令會很棒:
RETURN CANCEL;
或者甚至可以選擇“回滾”的行數(預設為全部):
RETURN CANCEL 10;