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

提交更正

如果您在文档中看到任何不正确、与您在使用特定功能时的体验不符或需要进一步澄清的内容,请使用此表格报告文档问题。