2012-10-29 70 views
1

我在PostgreSQL中創建了一個函數,它可以在幾個表上工作,並根據傳遞的參數來組裝結果。它工作得很好,從客戶的角度來看,它看起來像一個帶有附加參數的普通表(即它可以像通常的選擇查詢那樣被查詢)。Postgresql:觸發功能,使其可更新,就像一個可更新的視圖

爲了保持隱藏底層數據的信息,我還想創建一個寫入表的方法。我想我會創建一個觸發器,執行一個基本上會更新相關基礎表的函數。但是,我無法在函數上創建觸發器。除了桌子之外,還有什麼方法可以創建觸發器嗎?我也在考慮使用視圖(因爲我相信可以在視圖上創建觸發器),但是隨後我需要將該函數更改爲不適合的視圖,因爲我無法傳入視圖一個參數。

+0

對於將來的問題,如果你能顯示代碼和你的PostgreSQL版本,將不勝感激。例如,在這種情況下,您可能會顯示函數定義,您如何使用它以及您希望如何使用它。 –

回答

3

您似乎想要創建一個函數的可更新視圖的等效項,您可以在該函數上使用INSERT,UPDATEDELETE。這不可能。

如果您提供了類似功能的界面,請提供數據修改功能。

或者,把你的功能變成一個視圖。允許他們使用WHERE子句來限制視圖,而不是將參數傳遞給函數。然後使用視圖觸發器(PostgreSQL 9.1及更高版本)或規則(PostgreSQL 9.0及更低版本,如果可能,請勿在較新版本上使用)在視圖上啓用INSERT,UPDATEDELETE。請參閱CREATE TRIGGERCREATE RULE。規則很棘手,因此首選使用視圖觸發器。

PostgreSQL非常巧妙地將過濾器向下推入視圖,所以SELECT * FROM some_view WHERE some_col = 4通常不會掃描整個視圖然後對其進行過濾。它會將WHERE子句「推」到視圖的查詢中並執行該查詢。所以如果你的觀點是SELECT * FROM some_table WHERE NOT is_archived PostgreSQL實際上會執行相當於SELECT * FROM some_table WHERE (NOT is_archived) AND some_col = 4的執行。正因爲如此,當查詢視圖的幾行與所有行時,您可以並經常獲得完全不同的查詢計劃。 There's an example of this in a post I wrote a while ago

只是將您的函數包裝在視圖中將無法正常工作,除非它是一個STABLE而不是IMMUTABLE(因此可以內聯)的SQL函數。您最好從函數中提取SQL並基於相同的SQL創建視圖,而不是將其基於自身的函數。

如果你的函數參數沒有在簡單的WHERE子句中使用,那麼它會變得更加複雜,因爲沒有辦法像在函數中那樣將參數傳遞到視圖中。您可以創建一個關於參數的所有可能值的視圖,然後對其進行過濾,但如果Pg seq掃描視圖,則可能會導致非常糟糕的性能。在這些更復雜的情況下,我想提供一個函數調用接口來進行修改。

+0

真遺憾。我想爲INSERT,UPDATE,DELETE使用同名的'表名',並且也使用這些查詢的語法。如果我通過使用函數來處理這些函數,那麼我需要使用SELECT來執行這些函數,對吧? – Max

+0

@Max這是正確的,在PostgreSQL中運行函數需要'SELECT',因爲PostgreSQL沒有真正的可以用'CALL'調用的存儲過程。如果您使用這些API,則可以使用ODBC/JDBC調用轉義語法,例如JDBC'{call my_func(arguments)}'。無論如何,通過功能強制一切都很笨拙和緩慢;如果你的函數的參數只是用來設置一個'WHERE'子句,我會認真考慮一個可更新的視圖。 –

+0

@Max在一些答案詳細闡述。 –