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视图。 规则实际上只是一个命令转换机制,或者说命令宏。 这种转换发生在命令开始执行之前。如果你想要针对每个物理行独立发生的操作, 那么可能应该使用触发器而不是规则。有关规则系统的更多信息可以在 第 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)替代规则。
创建的规则名。它必须在同一个表上的所有规则名字中唯一。 同一个表上的同一个事件类型的规则是按照字母顺序运行的。
SELECT、INSERT、 UPDATE、DELETE事件之一。
规则作用的表或者视图的名字(可以有模式修饰)。
任意返回boolean的SQL条件表达式。 条件表达式除了引用NEW和OLD之外不能引用任何表, 并且不能有聚合函数。
INSTEAD指示使用该命令代替最初的命令。
ALSO指示该命令应该在最初的命令执行之后 一起执行。
如果既没有声明ALSO也没有声明INSTEAD, 那么ALSO是缺省。
组成规则动作的命令。有效的命令是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条件的行。 这是一个实现的限制,将来的版本应该修补这个毛病。