CREATE RULE — 定义一条新的重写规则
CREATE [ OR REPLACE ] RULEname
AS ONevent
TOtable_name
[ WHEREcondition
] DO [ ALSO | INSTEAD ] { NOTHING |command
| (command
;command
... ) } 其中event
可以是以下之一: SELECT | INSERT | UPDATE | DELETE
CREATE RULE
定义一条应用于指定表或视图的
新规则。CREATE OR REPLACE RULE
将创建一条
新规则或者替换同一个表上具有同一名称的现有规则。
LightDB规则系统允许我们定义
针对数据库表中插入、更新或者删除动作上的替代动作。大约来说,当在
一个给定表上执行给定命令时,一条规则会导致执行额外的命令。或者,
INSTEAD
规则可以用另一个命令替换给定的命令,或
者导致一个命令根本不被执行。规则也被用来实现 SQL 视图。规则实际上
是一种命令转换机制或者命令宏。这种转换会在命令的执行开始之前进行。
如果你实际上想要为每一个物理行独立地触发一个操作,你可能更需要一个
触发器而不是规则。更多有关规则系统的信息请见Chapter 41。
当前,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
之一。 注意包含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
查询将
被拒绝。
避免循环规则非常重要。例如,尽管下面的两条规则定义都被
LightDB所接受,
SELECT
命令将导致
LightDB报告一个错误,因为会产生一条
规则的递归扩展:
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
。这是一种实现限制,它可能会在未来的发行中被修复。
CREATE RULE
是一种
LightDB语言扩展,
整个查询重写系统也是这样。