=========== CREATE RULE =========== .. container:: refentry :name: SQL-CREATERULE .. container:: titlepage .. container:: refnamediv .. rubric:: CREATE RULE :name: create-rule CREATE RULE — 定义一条新的重写规则 .. container:: refsynopsisdiv .. rubric:: 大纲 :name: 大纲 .. code:: synopsis 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 .. container:: refsect1 :name: id-1.9.3.79.5 .. rubric:: 描述 :name: 描述 ``CREATE RULE``\ 定义一条应用于指定表或视图的 新规则。\ ``CREATE OR REPLACE RULE``\ 将创建一条 新规则或者替换同一个表上具有同一名称的现有规则。 PostgreSQL规则系统允许我们定义 针对数据库表中插入、更新或者删除动作上的替代动作。大约来说,当在 一个给定表上执行给定命令时,一条规则会导致执行额外的命令。或者, ``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``\ 查询)。 .. note:: .. rubric:: 注意 :name: 注意 :class: title 足够简单的视图自动就是可更新的(见\ `CREATE VIEW `__\ ),它们不需要依靠用户创建的规则来变成可 更新的。不过还是可以创建一条显式规则,自动更新转换通常比显式规则效 率高。 另一种值得考虑的办法是使用\ ``INSTEAD OF``\ 触发器(见 `CREATE TRIGGER `__\ )代替规则。 .. container:: refsect1 :name: id-1.9.3.79.6 .. rubric:: 参数 :name: 参数 .. container:: variablelist *``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``\ 被用来引 用被更新或者删除的现有行。 .. container:: refsect1 :name: id-1.9.3.79.7 .. rubric:: 注解 :name: 注解 要在表上创建或者修改规则,必须是表的拥有者。 在一条用于视图上\ ``INSERT``\ 、\ ``UPDATE`` 或者\ ``DELETE``\ 的规则中, 可以增加一个\ ``RETURNING`` 子句来发出视图的列。如果该规则被一个\ ``INSERT RETURNING``\ 、 ``UPDATE RETURNING``\ 或者 ``DELETE RETURNING``\ 命令触发,这个子句将被用来计算输出。 当规则被一个没有\ ``RETURNING``\ 的命令触发时,该规则的 ``RETURNING``\ 子句将被忽略。当前的实现只允许无条件 ``INSTEAD``\ 规则包含\ ``RETURNING``\ 。此外,用于同一事件 的所有规则中至多只能有一个\ ``RETURNING``\ 子句(这确保了只有一个 候选\ ``RETURNING``\ 子句被用来计算结果)。如果在任何可用规则中都 没有\ ``RETURNING``\ 子句,视图上的\ ``RETURNING``\ 查询将 被拒绝。 避免循环规则非常重要。例如,尽管下面的两条规则定义都被 PostgreSQL所接受, ``SELECT``\ 命令将导致 PostgreSQL报告一个错误,因为会产生一条 规则的递归扩展: .. code:: programlisting 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``\ 。 例如,在 .. code:: programlisting 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``\ 。这是一种实现限制,它可能会在未来的发行中被修复。 .. container:: refsect1 :name: id-1.9.3.79.8 .. rubric:: 兼容性 :name: 兼容性 ``CREATE RULE``\ 是一种 PostgreSQL语言扩展, 整个查询重写系统也是这样。 .. container:: refsect1 :name: id-1.9.3.79.9 .. rubric:: 另见 :name: 另见 `ALTER RULE `__, `DROP RULE `__