CREATE RULE
CREATE RULE — 定义一条新的重写规则
大纲
CREATE [ OR REPLACE ] RULEnameAS ONeventTOtable[ WHEREcondition] DO [ INSTEAD ]actionwhereactioncan be: NOTHING |query| (query;query... )
输入
name要创建的规则的名称。它必须与同一个表上任何其他规则的名称相区分。
event事件是
SELECT、UPDATE、DELETE或INSERT之一。table规则适用的表或视图的名称(可以是模式限定的)。
condition任意的 SQL 条件表达式(返回
boolean)。条件表达式不能引用new和old之外的任何表,并且不能包含聚合函数。query组成
action的一个或多个查询可以是任何 SQL 的SELECT、INSERT、UPDATE、DELETE或NOTIFY语句。
在 condition
和 action 中,可以使用特殊表名 new 和 old
来引用被引用表中的值。new 在 ON INSERT 和 ON UPDATE 规则中有效,用于引用正在被插入或更新的新行。old 在 ON UPDATE 和 ON DELETE
规则中有效,用于引用正在被更新或删除的现有行。
输出
CREATE RULE规则成功创建时返回的消息。
描述
CREATE RULE 为一个指定的表或视图定义一条新的规则。CREATE OR REPLACE RULE 要么创建一条新规则,要么替换同一个表上同名的现有规则。
PostgreSQL 的规则系统允许定义在对数据库表进行插入、更新或删除时所执行的替代动作。规则也用于实现表视图。
一条规则的语义是:当单个实例(行)被访问、插入、更新或删除时,会有一个旧实例(对于选择、更新和删除)和一个新实例(对于插入和更新)。给定事件类型和给定目标表的所有规则会被依次(按名称顺序)检查。如果
WHERE 子句中指定的
condition(如果有)为真,该规则的
action 部分就会被执行。如果指定了 INSTEAD,action
会替代原始查询执行;否则,对于 ON INSERT,它在原始查询之后执行,而对于 ON UPDATE 或 ON DELETE,它在原始查询之前执行。在 condition
和 action 两部分中,旧实例和/或新实例中字段的值会替换到
old.attribute-name
和 new.attribute-name 上。
规则的 action 部分可以由一个或多个查询组成。要编写多个查询,需用圆括号包围它们。这些查询会按指定的顺序执行。action 也可以是 NOTHING,表示没有任何动作。因此,一条 DO INSTEAD NOTHING 规则会阻止原始查询的执行(当其条件为真时);而一条 DO NOTHING 规则没有任何用处。
规则的 action 部分与触发激活它的用户命令使用相同的命令标识符和事务标识符执行。
必须认识到,规则实际上是一种查询转换机制,或者说查询宏。整个查询会被处理并转换为一系列包含规则动作的查询。这发生在查询开始求值之前。因此,有条件的规则是通过把规则条件加到由该规则导出的动作的 WHERE 子句中来处理的。上面把规则描述为对每一行执行的操作因而有一定的误导性。如果你真正需要的是对每个物理行独立触发的操作,那么你很可能应该使用触发器而不是规则。规则最适合那些需要独立于所处理的具体数据来转换整个查询的场合。
规则与视图
目前,ON SELECT 规则必须是无条件的 INSTEAD 规则,并且其动作必须由单个 SELECT 查询组成。因此,一条 ON SELECT 规则实际上会把表变为视图,其可见内容是该规则的 SELECT 查询返回的行,而不是表中原来存储的内容(如果有)。直接编写 CREATE VIEW 命令被认为比创建真实表并为其定义 ON SELECT 规则的风格更好。
CREATE VIEW会创建一个虚拟表(没有底层存储)并为其关联一条 ON SELECT 规则。系统不会允许对该视图的更新,因为它知道那里没有真实的表。你可以通过定义 ON INSERT、ON UPDATE 和 ON DELETE 规则(或其中足以满足你需求的任意子集),将视图上的更新动作替换为对其他表的适当更新,从而营造出可更新视图的效果。
如果你尝试对视图更新使用有条件规则,这里有一个陷阱:对于你希望允许在该视图上执行的每一种动作,必须都有一条无条件的 INSTEAD 规则。如果该规则是有条件的,或者不是 INSTEAD,那么系统仍会拒绝执行该更新动作的尝试,因为它认为在某些情况下最终可能还是会尝试在该虚拟表上执行该动作。如果你想用有条件规则处理所有有用的情况,可以;只需加上一条无条件的 DO INSTEAD NOTHING 规则,以确保系统明白它永远不会被要求去更新这个虚拟表。然后把这些有条件规则改为非 INSTEAD;在它们触发的情况下,它们会附加在默认的 INSTEAD NOTHING 动作之上。
注解
要在一个表上定义规则,你必须拥有该表的规则定义权限。使用 GRANT
和 REVOKE 来更改权限。
避免循环规则非常重要。例如,尽管下面两条规则定义中的每一条都被 PostgreSQL 接受,但 select 命令会导致 PostgreSQL 报告错误,因为查询循环了太多次:
CREATE RULE "_RETURN" AS
ON SELECT TO emp
DO INSTEAD
SELECT * FROM toyemp;
CREATE RULE "_RETURN" AS
ON SELECT TO toyemp
DO INSTEAD
SELECT * FROM emp;
这个从 EMP 中选择的尝试会导致
PostgreSQL 报错,因为这些查询循环了太多次:
SELECT * FROM emp;
当前,如果一个规则包含一个 NOTIFY 查询,该 NOTIFY 会被无条件执行 —— 也就是说,即使没有任何应当应用该规则的行,也会发出 NOTIFY。例如,在
CREATE RULE notify_me AS ON UPDATE TO mytable DO NOTIFY mytable;
UPDATE mytable SET name = 'foo' WHERE id = 42;
中,在 UPDATE 期间会发送一个 NOTIFY 事件,无论是否存在 id = 42 的行。这是一个实现限制,未来版本中可能会修复。
兼容性
SQL92
CREATE RULE 是 PostgreSQL
的语言扩展。SQL92 中没有 CREATE RULE 语句。