CREATE RULE — 定义一条新的重写规则
CREATE [ OR REPLACE ] RULEnameAS ONeventTOtable_name[ WHEREcondition] DO [ ALSO | INSTEAD ] { NOTHING |command| (command;command... ) } whereeventcan be one of: SELECT | INSERT | UPDATE | DELETE
CREATE RULE 定义一条应用于指定表或视图的新规则。CREATE OR REPLACE RULE 将创建一条新规则,或者替换同一表上同名的现有规则。
PostgreSQL 规则系统允许定义在对数据库表进行插入、更新或删除时要执行的替代动作。粗略地说,当在给定表上执行某个给定命令时,规则会使额外的命令被执行。另外,一条 INSTEAD 规则可以用另一个命令替换给定的命令,或者让某个命令根本不被执行。规则也被用来实现 SQL 视图。很重要的一点是要认识到,规则实际上是一种命令转换机制,也就是命令宏。转换发生在命令开始执行之前。如果你真正想要的是对每个物理行独立触发的操作,那么你很可能应该使用触发器而不是规则。有关规则系统的更多信息见 Chapter 39。
目前,ON SELECT 规则只能被附加到视图上。这样的规则必须被命名为 "_RETURN",必须是一条无条件的 INSTEAD 规则,并且其动作必须由单独一条 SELECT 命令构成。这条命令定义了视图的可见内容。(视图本身基本上是一个没有存储的虚拟表。)最好把这样的规则看作一种实现细节。虽然可以通过 CREATE OR REPLACE RULE "_RETURN" AS ... 重新定义视图,但使用 CREATE OR REPLACE VIEW 是更好的风格。
通过定义 ON INSERT、ON UPDATE 和 ON DELETE 规则(或者其中足以满足你需求的任意子集),用对其他表的适当更新来替换视图上的更新动作,你可以营造出可更新视图的假象。如果你想支持 INSERT RETURNING 等,那么务必把一个合适的 RETURNING 子句放进这些规则中的每一条。
如果你试图用条件规则来处理复杂的视图更新,有一个陷阱:对于你希望允许在视图上执行的每一种动作,都必须有一条无条件的 INSTEAD 规则。如果规则是条件性的,或者不是 INSTEAD,那么系统仍然会拒绝执行该更新动作的尝试,因为它认为在某些情况下可能最终会对视图的虚拟表执行该动作。如果你想在条件规则中处理所有有用的情况,可以添加一条无条件的 DO INSTEAD NOTHING 规则,以确保系统明白永远不会被要求更新虚拟表。然后把条件规则改成非 INSTEAD 的;在它们被应用的情况下,它们会在默认的 INSTEAD NOTHING 动作之外追加执行。(不过,这种方法目前还不能用来支持 RETURNING 查询。)
简单到足以自动可更新的视图(参见 CREATE VIEW)不需要用户创建的规则就能可更新。虽然你仍然可以创建显式规则,但自动更新转换通常会优于显式规则。
另一种值得考虑的替代方案是使用 INSTEAD OF 触发器(参见 CREATE TRIGGER)来代替规则。
name要创建的规则的名称。此名称必须与同一表上任何其他规则的名称不同。同一表上同一事件类型的多个规则会按名称的字母顺序被应用。
event 事件是 SELECT、INSERT、UPDATE 或 DELETE 之一。注意,一条 INSERT 如果含有 ON CONFLICT 子句,就不能用于带有 INSERT 或 UPDATE 规则的表。请考虑改用可更新视图。
table_name规则所应用的表或视图的名称(可以用模式限定)。
condition 任何 SQL 条件表达式(返回 boolean)。条件表达式不能引用除 NEW 和 OLD 之外的任何表,并且不能包含聚集函数。
INSTEADINSTEAD 表示这些命令应当取代原始命令被执行。
ALSOALSO 表示这些命令应当在原始命令之外也被执行。
如果既没有指定 ALSO 也没有指定 INSTEAD,则默认为 ALSO。
command 构成规则动作的一条或多条命令。有效的命令是 SELECT、INSERT、UPDATE、DELETE 或 NOTIFY。
在 condition 和 command 之中,可以使用特殊的表名 NEW 和 OLD 来引用被引用表中的值。NEW 在 ON INSERT 和 ON UPDATE 规则中有效,用于引用正在被插入或更新的新行。OLD 在 ON UPDATE 和 ON DELETE 规则中有效,用于引用正在被更新或删除的现有行。
你必须是表的拥有者才能为它创建或更改规则。
在用于视图上 INSERT、UPDATE 或 DELETE 的规则中,你可以添加一个发出视图列的 RETURNING 子句。如果规则分别由 INSERT RETURNING、UPDATE RETURNING 或 DELETE 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;
将会发送一个 NOTIFY 事件,它发生在 UPDATE 期间,无论是否存在匹配条件 id = 42 的行。这是一个可能会在未来的发行版中被修复的实现限制。
CREATE RULE 是 PostgreSQL 的一种语言扩展,整个查询重写系统也是如此。