Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (中文) » SQL Anywhere 服务器 - SQL 的用法 » 存储过程和触发器 » 使用过程、触发器和批处理 » 触发器简介 » 有关触发器的高级信息

 

INSTEAD OF 触发器

INSTEAD OF 触发器不同于 BEFORE 和 AFTER 触发器,因为当 INSTEAD OF 触发器触发时,会跳过触发操作而执行指定的操作。

INSTEAD OF 触发器独有的功能和限制列表如下:

  • 对于给定表中的每个触发事件,只能有一个 INSTEAD OF 触发器。

  • 可为表或视图定义 INSTEAD OF 触发器。但不能对实例化视图定义 INSTEAD OF 触发器,因为在实例化视图上不能执行 DML 操作(例如 INSERT、DELETE 和 UPDATE 语句)。

  • 当定义 INSTEAD OF 触发器时不能指定 ORDER 或 WHEN 子句。

  • 不能为 UPDATE OF column-list 触发事件定义 INSTEAD OF 触发器。请参见CREATE TRIGGER 语句

  • INSTEAD OF 触发器是否执行递归取决于该触发器的目标是基表还是视图。对于视图,发生递归;对于基表,则不发生。就是说,如果 INSTEAD OF 触发器在定义触发器的基表上执行 DML 操作,这些操作不会使触发器触发(包括 BEFORE 或 AFTER 触发器)。如果目标为视图,则在该视图上执行的操作会触发所有触发器。

  • 如果表中定义了 INSTEAD OF 触发器,则不能对该表执行带有 ON EXISTING 子句的 INSERT 语句。尝试此操作将返回 SQLE_INSTEAD_TRIGGER 错误。

  • 不能对使用 WITH CHECK OPTION 定义(或嵌套在以此方式定义的其它视图中)的视图,以及包含对其定义的 INSTEAD OF INSERT 触发器的视图执行 INSERT 语句。对于 UPDATE 和 DELETE 语句,这点也同样适用。尝试此操作将返回 SQLE_CHECK_TRIGGER_CONFLICT 错误。

  • 如果由于执行了定位更新、定位删除、PUT 语句或宽插入操作导致 INSTEAD OF 触发器被触发,则返回 SQLE_INSTEAD_TRIGGER_POSITIONED 错误。

使用 INSTEAD OF 触发器更新不可更新的视图

INSTEAD OF 触发器允许对非固有可更新视图执行 INSERT、UPDATE 或 DELETE 语句。触发器的主体定义执行相应 INSERT、UPDATE 或 DELETE 语句的意义。例如,假定您创建了以下视图:

CREATE VIEW V1 ( Surname, GivenName, State ) 
   AS SELECT DISTINCT Surname, GivenName, State 
        FROM Contacts;

不能从 V1 中删除行,因为 DISTINCT 关键字使得 V1 为非固有可更新。换言之,该数据库服务器无法明确地确定从 V1 中删除行的意义。但可定义实现 V1 上的删除操作的 INSTEAD OF DELETE 触发器。例如,当从 V1 中删除该行时,下面的触发器将从 Contacts 中删除具有给定 Surname、GivenName 和 State 的所有行:

CREATE TRIGGER V1_Delete
  INSTEAD OF DELETE ON V1
  REFERENCING OLD AS old_row
  FOR EACH ROW
BEGIN
    DELETE FROM Contacts
      WHERE Surname = old_row.Surname
        AND GivenName = old_row.GivenName
        AND State = old_row.State
END;

定义 V1_Delete 触发器后,就可以从 V1 中删除行了。还可以定义其它 INSTEAD OF 触发器,以允许对 V1 执行 INSERT 和 UPDATE 语句。

如果具有 INSTEAD OF DELETE 触发器的视图嵌套在其它视图中,则为了检查 DELETE 的可更新性,它会象基表一样被处理。对于 INSERT 和 UPDATE 操作,这点也同样适用。继续先前的示例,创建另一个视图:

CREATE VIEW V2 ( Surname, GivenName ) AS
  SELECT Surname, GivenName from V1;

没有 V1_Delete 触发器,不能从 V2 中删除行,因为 V1 不是固有可更新的,因此 V2 也不是。但是,如果对 V1 定义 INSTEAD OF DELETE 触发器,则可以从 V2 中删除行。每个从 V2 中删除的行都会导致一个行被从 V1 中删除,从而触发 V1_Delete 触发器。

对嵌套视图定义 INSTEAD OF 触发器时要谨慎,因为这些触发器的触发可能产生意外的结果。要使目标行为变为显式,则对引用该嵌套视图的任何视图定义 INSTEAD OF 触发器。

可对 V2 定义以下触发器以产生 DELETE 语句的所需行为:

CREATE TRIGGER V2_Delete
  INSTEAD OF DELETE ON V2
  REFERENCING OLD AS old_row
  FOR EACH ROW
BEGIN
    DELETE FROM Contacts
      WHERE Surname = old_row.Surname
        AND GivenName = old_row.GivenName
END;

V2_Delete 触发器可确保对 V2 的删除操作保持不变,即使 V1 上的 INSTEAD OF DELETE 触发器被删除或更改。