如果要使用函數來處理查詢中的結果集,最好的選擇是SELECT ... INTO TEMPORARY TABLE
,然後用臨時表名稱調用該函數。
在PostgreSQL函數中使用行集的難度令人惱火,因爲給定的瑣碎行集是多少。我意識到要做到這一點的唯一方法是使用refcursor,處理臨時表,或通過實現聚合或窗口函數。後兩個選項不允許您控制返回的行數,因此它們不適合您的目的。
函數不能引用調用該函數的CTE中的公用表表達式別名,因此您不能使用CTE創建虛擬表並將表名傳遞給該函數。例如顯示它不工作:
CREATE OR REPLACE FUNCTION dynsql(tname text, colname text) RETURNS SETOF RECORD AS
$$
BEGIN
RETURN QUERY EXECUTE format('SELECT %I FROM %I', colname, tname);
END;
$$ LANGUAGE plpgsql;
WITH dummy(col) AS (VALUES (1),(2),(3))
SELECT * FROM dynsql('dummy','col') t(id integer);
結果:
ERROR: relation "dummy" does not exist
...因爲在WITH
表達的別名是本地WITH
表達。 (能夠從函數中引用它會很好,但是這也會產生各種令人興奮的名稱衝突問題和SECURITY DEFINER
函數的安全問題。)
儘管可以編寫PL/PgSQL函數這會消耗一個refcursor,這需要你帶一個查詢的遊標並將它傳遞給該函數。你不能只使用普通的函數調用語法。它的效率也很低,需要在函數中使用LOOP
。我認爲這不會有太大的幫助。
實現該功能時,請使用EXECUTE format(...) USING ...
來保持動態SQL不太可怕。見this earlier answer。
雖然有一些缺點 - 如果你做出這樣的功能,你將無法在查詢中使用預準備語句,而且你需要在客戶端引用你的查詢參數,這很容易搞砸。 – Tometzky
@Tometzky是的。這是一個潛在的巨大SQL注入安全漏洞,要求客戶端對標識符引用等非常偏執。 –