🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# CREATE RULE ## Name CREATE RULE -- 定义一个新重写规则 ## Synopsis ``` CREATE [ OR REPLACE ] RULE _name_ AS ON _event_ TO _table_name_ [ WHERE _condition_ ] DO [ ALSO | INSTEAD ] { NOTHING | _command_ | ( _command_ ; _command_ ... ) } ``` ## 描述 `CREATE RULE`定义一个适用于特定表或者视图的新规则。 `CREATE OR REPLACE RULE`要么是创建一个新规则, 要么是替换一个表上的同名规则。 PostgreSQL规则系统允许在更新、插入、 删除时执行一个其它的预定义动作。简单的说, 规则就是在指定表上执行指定动作的时候,将导致一些额外的动作被执行。 另外,一个`INSTEAD`规则可以用另外一个命令取代特定的命令, 或者令完全不执行该命令。规则还可以用于实现SQL视图。 规则实际上只是一个命令转换机制,或者说命令宏。 这种转换发生在命令开始执行之前。如果你想要针对每个物理行独立发生的操作, 那么可能应该使用触发器而不是规则。有关规则系统的更多信息可以在 [Chapter 38](#calibre_link-472)找到。 目前,`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`查询。) > **Note:** 一个足够简单可以自动更新的视图(参阅[CREATE VIEW](#calibre_link-473)) 不需要用户创建的使其可更新的规则。不过,你可以创建一个明确的规则, 自动更新转换通常比明确的规则执行的更好。 > > 另一个可替换的价值考虑是使用`INSTEAD OF`触发器 (参阅[CREATE TRIGGER](#calibre_link-459))替代规则。 ## 参数 `_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](#calibre_link-474), [DROP RULE](#calibre_link-475)