PostgreSQL 9.4.4 中文手册
上一页 | 上一级 |  | 下一页

# CREATE RULE

## 名称

CREATE RULE -- 定义一个新重写规则

## 大纲

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

    这里的event可以是下列之一：

        SELECT | INSERT | UPDATE | DELETE

## 描述

`CREATE RULE`定义一个适用于特定表或者视图的新规则。 `CREATE OR REPLACE RULE`要么是创建一个新规则， 要么是替换一个表上的同名规则。

PostgreSQL规则系统允许在更新、插入、 删除时执行一个其它的预定义动作。简单的说， 规则就是在指定表上执行指定动作的时候，将导致一些额外的动作被执行。 另外，一个`INSTEAD`规则可以用另外一个命令取代特定的命令， 或者令完全不执行该命令。规则还可以用于实现SQL视图。 规则实际上只是一个命令转换机制，或者说命令宏。 这种转换发生在命令开始执行之前。如果你想要针对每个物理行独立发生的操作， 那么可能应该使用触发器而不是规则。有关规则系统的更多信息可以在 第 38 章找到。

目前，`ON SELECT`规则必须是无条件的`INSTEAD` 规则并且必须有一个由单独一条`SELECT`查询组成的动作。 因此，一条`ON SELECT`规则有效地把表转成视图， 它的可见内容是规则的`SELECT` 查询返回的记录而不是存储在表（如果有）中的内容。写一条 `CREATE VIEW`命令比创建一个表然后在上面定义一条 `ON SELECT`规则的风格要好。

你可以创建一个允许更新的视图的幻觉，方法是在视图上定义`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`事件之一。

`table_name`

  规则作用的表或者视图的名字(可以有模式修饰)。

`condition`

  任意返回`boolean`的SQL条件表达式。 条件表达式除了引用`NEW`和`OLD`之外不能引用任何表， 并且不能有聚合函数。

`INSTEAD`

  `INSTEAD`指示使用该命令代替最初的命令。

`ALSO`

  `ALSO`指示该命令应该在最初的命令执行之后 一起执行。

  如果既没有声明`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 语言的扩展，整个规则重写系统都是如此。

## 又见

ALTER RULE, DROP RULE

上一页 | 起始页 | 下一页
CREATE ROLE | 上一级 | CREATE SCHEMA