CREATE RULE
用于定义一条应用于指定表或视图的新规则。
简介
CREATE RULE
定义一条应用于指定表或视图的新规则。CREATE OR REPLACE RULE
将创建一条新规则或者替换同一个表上具有同一名称的现有规则。
PolarDB规则系统允许我们定义针对数据库表中插入、更新或者删除动作上的替代动作。大约来说,当在一个给定表上执行给定命令时,一条规则会导致执行额外的命令。或者, INSTEAD
规则可以用另一个命令替换给定的命令,或者导致一个命令根本不被执行。规则也被用来实现 SQL 视图。规则实际上是一种命令转换机制或者命令宏。这种转换会在命令的执行开始之前进行。 如果你实际上想要为每一个物理行独立地触发一个操作,你可能更需要一个触发器而不是规则。
当前,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 [ 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 VIEW),它们不需要依靠用户创建的规则来变成可更新的。不过还是可以创建一条显式规则,自动更新转换通常比显式规则效率高。
另一种值得考虑的办法是使用INSTEAD OF
触发器(见 CREATE TRIGGER)代替规则。
参数
name
要创建的规则的名称。它必须与同一个表上任何其他规则的名称相区分。 同一个表上同一种事件类型的多条规则会按照其名称的字符顺序被应用。event
时间是SELECT
、INSERT
、UPDATE
或者DELETE
之一。 注意包含ON CONFLICT
子句的INSERT
不能被用在具有INSERT
或者UPDATE
规则的表上。那种情况下请考虑使用可更新的视图。table_name
规则适用的表或者视图的名称(可以是模式限定的)。condition
任意的 SQL 条件表达式(返回boolean
)。该条件表达式不能引用除NEW
以及OLD
之外的任何表,并且不能包含聚集函数。INSTEAD
INSTEAD
指示该命令应该取代 原始命令被执行。ALSO
ALSO
指示应该在原始命令 之外执行这些命令。如果
ALSO
和INSTEAD
都没有被指定, 默认是ALSO
。command
组成规则动作的命令。可用的命令有SELECT
、INSERT
、UPDATE
、DELETE
或者NOTIFY
。在
condition
和command
中,名为NEW
和OLD
的表可以被用来引用被引用表中的值。在ON INSERT
和ON UPDATE
规则中,NEW
被用来引用被插入或者更新的新行。在ON UPDATE
和ON DELETE
规则中,OLD
被用来引用被更新或者删除的现有行。
说明
要在表上创建或者修改规则,必须是表的拥有者。
在一条用于视图上INSERT
、UPDATE
或者DELETE
的规则中, 可以增加一个RETURNING
子句来发出视图的列。如果该规则被一个INSERT RETURNING
、 UPDATE RETURNING
或者 DELETE RETURNING
命令触发,这个子句将被用来计算输出。 当规则被一个没有RETURNING
的命令触发时,该规则的 RETURNING
子句将被忽略。当前的实现只允许无条件 INSTEAD
规则包含RETURNING
。此外,用于同一事件的所有规则中至多只能有一个RETURNING
子句(这确保了只有一个候选RETURNING
子句被用来计算结果)。如果在任何可用规则中都没有RETURNING
子句,视图上的RETURNING
查询将被拒绝。
避免循环规则非常重要。例如,尽管下面的两条规则定义都被 PolarDB所接受, SELECT
命令将导致 PolarDB报告一个错误,因为会产生一条规则的递归扩展:
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
。这是一种实现限制,它可能会在未来的发行中被修复。