2025年9月25日: PostgreSQL 18 釋出!
支援的版本:當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

CREATE RULE

CREATE RULE — 定義一個新重寫規則

概要

CREATE [ OR REPLACE ] RULE name AS ON event
    TO table_name [ WHERE condition ]
    DO [ ALSO | INSTEAD ] { NOTHING | command | ( command ; command ... ) }

where event can be one of:

    SELECT | INSERT | UPDATE | DELETE

描述

CREATE RULE 定義一個應用於指定表或檢視的新規則。CREATE OR REPLACE RULE 將會建立一個新規則,或者替換掉同一表上同名的現有規則。

PostgreSQL 規則系統允許為插入、更新或刪除資料庫表的操作定義一個替代動作。大致來說,當一個給定表上的給定命令被執行時,規則會引起額外的命令被執行。另外,INSTEAD 規則可以被另一個命令替換,或者根本不執行該命令。規則也用於實現 SQL 檢視。重要的是要認識到規則實際上是一種命令轉換機制,或者說是命令宏。這種轉換髮生在命令執行開始之前。如果你實際想要一個獨立於每個物理行而觸發的操作,你可能需要使用觸發器,而不是規則。關於規則系統的更多資訊,請參見第 39 章

目前,ON SELECT 規則只能附加到檢視上。這樣的規則必須命名為"_RETURN",必須是無條件的INSTEAD 規則,並且其動作必須是一個單獨的SELECT 命令。這個命令定義了檢視的可見內容。(檢視本身基本上是一個沒有儲存的虛擬表。)最好將這樣的規則視為一個實現細節。雖然可以透過CREATE OR REPLACE RULE "_RETURN" AS ...重新定義檢視,但使用CREATE OR REPLACE VIEW是更好的風格。

你可以透過定義ON INSERTON UPDATEON DELETE 規則(或這些規則的任意足夠你使用的子集)來替換檢視上的更新操作,從而在其他表上執行相應的更新,以此來模擬一個可更新的檢視。如果你想支援INSERT RETURNING 等,那麼請確保在這些規則中的每一箇中都包含一個合適的RETURNING 子句。

如果你嘗試對複雜的檢視更新使用條件規則,會有一個陷阱:對於你想允許在檢視上執行的每個操作,必須有一個無條件的INSTEAD 規則。如果規則是有條件的,或者不是INSTEAD,那麼系統仍然會拒絕執行更新操作的嘗試,因為它認為在某些情況下它可能會嘗試在檢視的虛擬表上執行該操作。如果你想在條件規則中處理所有有用的情況,請新增一個無條件的DO INSTEAD NOTHING 規則,以確保系統知道它永遠不會被呼叫來更新虛擬表。然後將條件規則設為非INSTEAD;在它們被應用的情況下,它們會新增到預設的INSTEAD NOTHING 動作中。(不過,此方法目前不支援RETURNING 查詢。)

注意

一個足夠簡單(參見CREATE VIEW)的檢視不需要使用者建立的規則就可以進行更新。雖然你仍然可以建立一個顯式的規則,但自動更新轉換通常會比顯式規則效能更好。

另一個值得考慮的替代方案是使用INSTEAD OF 觸發器(參見CREATE TRIGGER)來代替規則。

引數

name

要建立的規則的名稱。該名稱必須與同一表上任何其他規則的名稱不同。同一表和同一事件型別的多個規則按字母順序應用。

event

事件是 SELECTINSERTUPDATEDELETE 之一。請注意,包含 ON CONFLICT 子句的 INSERT 不能用於具有 INSERTUPDATE 規則的表。考慮使用可更新的檢視。

table_name

規則應用的表或檢視的名稱(可選模式限定)。

condition

AnySQL條件表示式(返回boolean)。條件表示式不能引用除 NEWOLD 以外的任何表,也不能包含聚合函式。

INSTEAD

INSTEAD 表示命令應該被執行而不是原始命令。

ALSO

ALSO 表示命令應該被執行在原始命令之外(即,附加執行)。

如果未指定 ALSOINSTEAD,則預設值為 ALSO

command

構成規則動作的命令或命令集。有效的命令是 SELECTINSERTUPDATEDELETENOTIFY

conditioncommand中,可以使用特殊表名 NEWOLD 來引用被引用表中的值。NEWON INSERTON UPDATE 規則中有效,用於引用正在插入或更新的新行。OLDON UPDATEON DELETE 規則中有效,用於引用正在更新或刪除的現有行。

註釋

要建立或更改表的規則,你必須是該表的所有者。

在檢視上的 INSERTUPDATEDELETE 規則中,你可以新增一個 RETURNING 子句,該子句會發出檢視的列。如果規則是由 INSERT RETURNINGUPDATE RETURNINGDELETE RETURNING 命令觸發的,則將使用此子句來計算輸出。當規則由不帶 RETURNING 的命令觸發時,規則的 RETURNING 子句將被忽略。當前實現只允許無條件的 INSTEAD 規則包含 RETURNING;此外,對於同一事件的所有規則,最多隻能有一個 RETURNING 子句。(這確保了只有一個候選 RETURNING 子句可用於計算結果。)如果任何可用規則中沒有 RETURNING 子句,則對檢視的 RETURNING 查詢將被拒絕。

非常重要的是要小心避免迴圈規則。例如,雖然下面的兩個規則定義都被 PostgreSQL 接受,但是 SELECT 命令會導致 PostgreSQL 報告一個錯誤,因為規則的遞迴展開

CREATE RULE "_RETURN" AS
    ON SELECT TO t1
    DO INSTEAD
        SELECT * FROM t2;

CREATE RULE "_RETURN" AS
    ON SELECT TO t2
    DO INSTEAD
        SELECT * FROM t1;

SELECT * FROM t1;

目前,如果規則動作包含 NOTIFY 命令,NOTIFY 命令將無條件執行,也就是說,即使沒有需要規則應用的任何行,NOTIFY 也會被髮出。例如,在

CREATE RULE notify_me AS ON UPDATE TO mytable DO ALSO NOTIFY mytable;

UPDATE mytable SET name = 'foo' WHERE id = 42;

執行 UPDATE 時會發送一個 NOTIFY 事件,無論是否有任何行匹配條件 id = 42。這是一個實現限制,未來版本可能會修復。

相容性

CREATE RULE 是 PostgreSQL 語言的擴充套件,整個查詢重寫系統也是如此。

另請參閱

ALTER RULE, DROP RULE

提交更正

如果您在文件中看到任何不正確、與您在使用特定功能時的體驗不符或需要進一步澄清的內容,請使用此表格報告文件問題。