我一再遇到這個問題,並沒有找到一個的解決方案。
我最近的做法是將返回的SET的第一行定義爲元數據,即第一個行。你的方法列表中沒有那個。 應用程序使用第一行進行簿記。實際數據從第二行開始。
一個明顯的缺點:你必須處理你的元數據中必須擠壓的任何行定義。不過,一個簡單的總數將適用於任何數字或字符串類型。
當然,您必須特別處理應用程序中的第一行。
CREATE OR REPLACE FUNCTION f_paginate(_max_id int, _limit int = 20
, _offset int = 0)
RETURNS TABLE(foo_id int, foo text) AS
$BODY$
BEGIN
SELECT INTO foo_id count(*)::int
FROM foo f
WHERE f.foo_id < _max_id; -- get count
RETURN NEXT; -- use first row for meta-data
RETURN QUERY -- actual data starts with second row
SELECT f.foo_id, f.foo
FROM foo f
WHERE f.foo_id < _max_id
LIMIT _limit
OFFSET _offset;
END;
$BODY$
LANGUAGE plpgsql;
呼叫:
這個簡單的例子從定義的表foo
作爲
CREATE TABLE foo (
foo_id serial PRIMARY KEY
,foo text
);
頁尺寸是20行,在函數頭部每默認預設返回行
SELECT * FROM f_paginate(100);
返回:
foo_id | foo
-------+----
86 | <NULL> <-- first row = meta-data
1 | bar <-- actual data
2 | baz
... 18 more ...
顯然,這種方法可以節省一些帶寬更高的_limit(頁面大小)。只有幾行,這是不值得的開銷。
的另一種方法是你「辦法一」 - 冗餘添加一列:
CREATE OR REPLACE FUNCTION f_paginate2(_max_id int, _limit int = 20
, _offset int = 0)
RETURNS TABLE(foo_id int, foo text, ct bigint) AS
$BODY$
BEGIN
RETURN QUERY
SELECT f.foo_id, f.foo, count(*) OVER()
FROM foo f
WHERE f.foo_id < _max_id
LIMIT _limit
OFFSET _offset;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
電話:
SELECT * FROM f_paginate2(100);
返回:
foo_id | foo | ct
-------+-----+----
1 | bar | 86
2 | baz | 86
... 18 more ...
表現非常在這種簡單的情況下類似。第一個查詢稍快,但可能只是因爲count(*) OVER()
減慢了第二個查詢。一個單獨的運行只有count(*)
更快。
*請停止創建'postgres-9.1'標籤。 'postgresql-9.1'存在,並且是正確的引導拼寫。 – Charles
問題是PostgreSQL有*函數*而不是*存儲過程*。最接近你可以進入一個函數的是返回一個'SETUP refcursor',但你仍然需要通過光標並顯示結果;如果這是另一個功能,那麼你又回到了同一條船上。開發人員一直在思考如何提供存儲過程(除了函數),但是還有一些技術問題與事務管理有關,這些問題還沒有被整理出來。 – kgrittn
@kgrittn可能會混淆錯字;這將是'SETOF refcursor'而不是'SETUP refcursor'' –