CREATE TRIGGER 语句

CREATE TRIGGER语句用于在数据库中定义触发器。 可以创建触发器以支持一般形式的完整性或业务规则。 触发器定义了一组由INSERT、UPDATE或DELETE语句执行或触发的操作。

调用

此语句可以嵌入在应用程序中,也可通过动态 SQL 语句来发出。 它是一个可执行语句,仅当 DYNAMICRULES 运行行为对于程序包有效时才能动态编译 (SQLSTATE 42509)。

授权

语句授权标识所拥有的特权必须至少包括下列其中一项权限:
  • 对定义了 BEFORE 或 AFTER 触发器的表的 ALTER 特权
  • 对定义 INSTEAD OF 触发器的视图的 CONTROL 特权
  • 定义 INSTEAD OF 触发器的视图的所有者
  • 对定义了触发器的表或视图的模式的 ALTERIN 特权
  • SCHEMAADM 定义触发器的表或视图所在的架构的权限
  • DBADM 权限
以及下列其中一项:
  • 数据库上的 IMPLICIT_SCHEMA 权限 (如果触发器的隐式或显式模式名不存在)
  • 对模式的 CREATEIN 特权 (如果触发器的模式名称引用现有模式)
  • SCHEMAADM 模式权限,如果触发器的模式名称引用了现有模式
  • DBADM 权限
如果该语句的授权标识没有 DATAACCESS 权限,那么只要触发器存在,该语句的授权标识所拥有的特权 (不包括组特权) 必须包含下列所有权限:
  • 在定义了触发器的表上,如果指定了任何转换变量或表:
    • 对定义了触发器的表的 SELECT 特权 (如果指定了任何转换变量或表)
    • SELECTIN 特权,用于包含定义触发器的表(如果有指定过渡变量或表)的架构
    • 对定义了触发器的表的 CONTROL 特权 (如果指定了任何转换变量或表)
    • 数据访问权限,用于包含触发器定义表的架构,如果指定了过渡变量或表
    • DATAACCESS 权限
  • 在触发的操作条件中引用的任何表或视图上:
    • 对触发的操作条件中引用的任何表或视图的 SELECT 特权
    • SELECTIN 特权,用于包含触发操作条件中引用的任何表或视图的模式
    • 对触发的操作条件中引用的任何表或视图的 CONTROL 特权
    • DATAACCESS 触发操作条件中引用的任何表或视图的架构权限
    • DATAACCESS 权限
  • 调用指定的触发式 SQL 语句所必需的特权。

对于 CREATE TRIGGER 语句中指定的任何表或视图,不考虑组特权。

要替换现有触发器,语句的授权标识必须是现有触发器的所有者 (SQLSTATE 42501)。

如果指定了安全选项,那么语句的授权标识所拥有的特权还必须包含 SECADM 或 CREATE_SECURE_OBJECT 权限 (SQLSTATE 42501)。

语法

Read syntax diagramSkip visual syntax diagramCREATEOR REPLACE TRIGGERtrigger-nameNO CASCADEBEFOREAFTERINSTEAD OFtrigger-eventON table-nameview-name REFERENCING12OLDAScorrelation-nameNEWAScorrelation-nameOLD TABLEASidentifierNEW TABLEASidentifierFOR EACH ROW3FOR EACH STATEMENTNOT SECUREDSECUREDtriggered-action
trigger-event
Read syntax diagramSkip visual syntax diagramORINSERTDELETEUPDATEOF,column-name4
triggered-action
Read syntax diagramSkip visual syntax diagram5WHEN(search-condition)label:SQL-procedure-statement
SQL-procedure-statement
Read syntax diagramSkip visual syntax diagramCALLCompound SQL (compiled)6Compound SQL (inlined)FORWITH,common-table-expressionfullselectGET DIAGNOSTICSIFINSERTITERATELEAVEMERGEsearched-deletesearched-updateSET VariableSIGNALWHILE
Notes:
  • 1 OLD and NEW can only be specified once each.
  • 2 OLD TABLE and NEW TABLE can only be specified once each, and only for AFTER triggers or INSTEAD OF triggers.
  • 3 FOR EACH STATEMENT may not be specified for BEFORE triggers or INSTEAD OF triggers.
  • 4 A trigger event must not be specified more than once for the same operation. For example, INSERT OR DELETE is allowed, but INSERT OR INSERT is not allowed.
  • 5 WHEN condition may not be specified for INSTEAD OF triggers.
  • 6 A compound SQL (compiled) statement cannot be specified if the trigger definition includes a REFERENCING OLD TABLE clause or a REFERENCING NEW TABLE clause. A compound SQL (compiled) statement also cannot be specified for a trigger definition in a partitioned database environment.

描述

OR REPLACE
指定如果当前服务器上已存在触发器定义,那么替换该定义。 在目录中替换新定义之前,将有效地删除现有定义。 如果当前服务器上不存在触发器定义,那么将忽略此选项。 此选项只能由对象所有者指定。
触发器名称
指定触发器的名称。 此名称(包括隐式或显式的模式名)不能标识已在目录中描述的触发器 (SQLSTATE 42710)。 如果指定了两部分名称,那么模式名称不能以 SYS 开头 (SQLSTATE 42939)。
之前无级联
指定在将主题表的实际更新所引起的任何更改应用于数据库之前执行相关联的触发操作。 它还指定触发器的触发操作不会导致激活其他触发器。
AFTER
指定在将主题表的实际更新所引起的更改应用于数据库之后执行相关联的触发操作。
INSTEAD OF
指定由相关联的触发操作替换对主题视图的操作。 给定主题视图上的每种操作都只允许一个 INSTEAD OF 触发器 (SQLSTATE 428FP)。
触发器事件
指定每当其中一个事件应用于主题表或主题视图时将执行与触发器关联的触发操作。 可以指定事件的任意组合,但每个事件 (INSERT , DELETE 和 UPDATE) 只能指定一次 (SQLSTATE.42613)。 如果指定了多个事件,那么触发的操作必须是复合 SQL (已编译) 语句 (SQLSTATE 42601)。
INSERT
指定每当对主题表或主题视图应用 INSERT 操作时,都将执行与触发器相关联的触发操作。
删除
指定每当将 DELETE 操作应用于主题表或主题视图时将执行与触发器关联的触发操作。
UPDATE
指定每当对主题表或主题视图应用 UPDATE 操作时,将执行与触发器关联的触发式操作,此操作遵循指定或隐含的列。
如果未指定可选的 column-name 列表,那么隐含表或视图的每列。 因此,省略 column-name 列表意味着将通过更新表或视图的任何列来激活触发器。
OF column-name, ...
指定的每个 column-name 都必须是基本表的列 (SQLSTATE 42703)。 如果此触发器是 BEFORE 触发器,那么指定的 列名 不能是除标识列以外的生成列 (SQLSTATE 42989)。 列名 不能在 列名 列表中多次出现 (SQLSTATE 42711)。 仅当更新 列名 列表中标识的列时,才将激活此触发器。 不能对 INSTEAD OF 触发器指定此子句 (SQLSTATE 42613)。
ON
table-name
指定 BEFORE 触发器或 AFTER 触发器定义的主题表。 此名称必须指定基本表或者解析为基本表的别名(SQLSTATE 42704 或 42809)。 该名称不得指定目录表 (SQLSTATE 42832) ,具体化查询表 (SQLSTATE 42997) , 创建的临时表, 声明的临时表 (SQLSTATE 42995) 或昵称 (SQLSTATE 42809)。
视图名称
指定 INSTEAD OF 触发器定义的主题视图。 该名称必须指定无类型视图或解析为无类型视图 且没有类型为 XML 的列的别名 (SQLSTATE 42704 或 42809)。 该名称不得指定目录视图 (SQLSTATE 42832)。 该名称不得指定使用 WITH CHECK OPTION (对称视图) 定义的视图,也不得指定直接或间接定义了对称视图的视图 (SQLSTATE 428FQ)。
NOT SECURED 或 SECURED
指定触发器是否视为安全触发器。 缺省值为 NOT SECURED。
NOT SECURED
指定触发器被认为不安全。
SECURED
指定触发器被视为安全触发器。 对于其主题表是已激活行级别或列级别访问控制的表的触发器,必须指定 SECURED (SQLSTATE 428H8)。 同样,必须为在视图上创建的触发器指定 SECURED,并且该视图定义中的一个或多个底层表已激活行级别或列级别访问控制 (SQLSTATE 428H8)。
REFERENCING
指定 转换变量 的相关名和 转换表的表名。 相关名标识触发 SQL 操作所影响的行集中的特定行。 表名标识受影响行的完整集合。 触发 SQL 操作影响的每一行都适用于被触发的操作,方法是通过指定 correlation-names 来限定列,如下所示。
OLD AS 相关名
指定在触发 SQL 操作之前标识行状态的相关名称。
新增 AS correlation-name
指定一个关联名,该关联名标识由触发 SQL 操作和已执行的 BEFORE 触发器中的任何 SET 语句修改的行状态。

通过使用如下指定的临时表名,受触发 SQL 操作影响的完整行集可供触发操作使用。

OLD TABLE AS 标识
指定临时表的名称,该表在触发 SQL 操作之前标识完整的受影响行集中的值。 如果触发器事件为 INSERT ,那么临时表为空。
新增 TABLE AS 标识
指定临时表的名称,该临时表标识由触发 SQL 操作以及已执行的前触发器中的任何 SET 语句修改的完整受影响行集的状态。 如果触发器事件为 DELETE ,那么临时表为空。
以下规则适用于 REFERENCING 子句:
  • OLD 和 NEW 相关名称以及 OLD TABLE 和 NEW TABLE 名称都不能相同 (SQLSTATE 42712)。
  • 只能为触发器指定一个 OLD 和一个 NEW 相关名 (SQLSTATE 42613)。
  • 只能为触发器指定一个 OLD TABLE 和一个 NEW TABLE identifier (SQLSTATE 42613)。
  • 不能在 BEFORE 触发器中定义 OLD TABLE 或 NEW TABLE 标识 (SQLSTATE 42898)。
  • NEW 转换变量只能是 BEFORE 触发器中赋值的目标。 否则,转换变量不能是赋值的目标 (SQLSTATE 42703 或 42987)。
  • 不能在 FOR EACH STATEMENT 触发器中定义 OLD 或 NEW 相关名 (SQLSTATE 42899)。
  • 无法修改转换表 (SQLSTATE 42807)。
  • 触发操作中对转换表列和转换变量的引用总数不能超过表中列数的限制,或者它们的长度总和不能超过表中行的最大长度 (SQLSTATE 54040)。
  • 每个 correlation-name 和每个 标识 的作用域都是整个触发器定义。
  • 如果触发操作包含复合 SQL (已编译) 语句:
    • 不能定义 OLD TABLE 或 NEW TABLE 标识。
    • 如果操作是 DELETE 操作,那么 OLD correlation-name 将捕获已删除行的值。 如果它是 UPDATE 操作,那么它将在 UPDATE 操作之前捕获行的值。 对于插入操作, OLD correlation-name 会捕获一行中每个列的空值。
    • 对于插入操作或更新操作, NEW 值将捕获原始操作提供的行的新状态,以及已执行至此点的任何 BEFORE 触发器所修改的行的新状态。 对于删除操作,新的 correlation-name 将捕获一行中每个列的空值。 在 BEFORE DELETE 触发器中,分配给新转换变量的任何非空值仅在发生分配的触发器中持久存储。
  • 如果触发式操作不包含复合 SQL (编译型) 语句:
    • 仅当触发器事件是 DELETE 操作或 UPDATE 操作 (SQLSTATE 42898) 时,才能使用 OLD correlation-name 和 OLD TABLE identifier 。 如果操作是 DELETE 操作,那么 OLD correlation-name 将捕获已删除行的值。 如果它是 UPDATE 操作,那么它将在 UPDATE 操作之前捕获行的值。 这同样适用于 OLD TABLE identifier 和受影响行的集合。
    • 仅当触发器事件是 INSERT 操作或 UPDATE 操作 (SQLSTATE 42898) 时,才能使用 NEW correlation-name 和 NEW TABLE identifier 。 在这两个操作中, NEW 的值会捕获行的新状态,如原始操作所提供的状态,以及已执行至此点的任何 BEFORE 触发器所修改的状态。 这同样适用于 NEW TABLE identifier 和受影响行的集合。
FOR EACH ROW
指定将对受触发 SQL 操作影响的主题表或主题视图的每行应用一次触发操作。
FOR EACH STATEMENT
指定对整个语句仅应用触发操作一次。 不能对 BEFORE 触发器或 INSTEAD OF 触发器指定此类型的触发器粒度 (SQLSTATE 42613)。 如果指定了 UPDATE 或 DELETE 触发器,那么将激活该触发器,即使触发 UPDATE 或 DELETE 语句未影响任何行也是如此。
触发操作
指定激活触发器时要执行的操作。 触发式操作由 SQL-procedure-statement 和执行 SQL-procedure-statement的可选条件组成。

触发器事件谓词可以在 CREATE TRIGGER 语句的触发操作中的任何位置使用,该语句使用复合 SQL (已编译) 语句作为 SQL-procedure-statement

WHEN
(搜索条件)
指定具有 true 或 false 值或者未知值的条件。 搜索条件 使您能够确定是否应该执行特定的触发操作。 仅当指定的搜索条件求值为 true 时,才会执行相关联的操作。 如果省略了 WHEN 子句,那么将始终执行关联的 SQL-procedure-statement

不能为 INSTEAD OF 触发器指定 WHEN 子句 (SQLSTATE 42613)。

对具有 XML 数据类型的转换变量的引用只能在审定谓词中使用。

标签:
指定 SQL 过程语句的标签。 该标签在 SQL 过程语句列表中必须是唯一的,包括嵌套在列表中的任何复合语句。 请注意,未嵌套的复合语句可以使用相同的标签。 SQL 过程语句列表可以包含在许多 SQL 控制语句中。

只有 FOR 语句, WHILE 语句和复合 SQL 语句可以包含标签。

SQL-procedure-statement
指定要作为触发操作的一部分的 SQL 语句。 不支持对复合 SQL 中的昵称执行搜索更新,搜索删除,插入或合并操作。

BEFORE 触发器对类型为 XML 的列的触发操作可以通过 SET 语句调用 XMLVALIDATE 函数,使类型为 XML 的值保持不变,或者 使用 SET 语句将其分配给 NULL

SQL-procedure-statement 不得包含不受支持的语句 (SQLSTATE 42987)。

SQL-procedure-statement 无法引用未定义的转换变量 (SQLSTATE 42703) ,联合对象 (SQLSTATE 42997) 或声明的临时表 (SQLSTATE 42995)。 或 BUSINESS_TIME 时间段的开始和结束列 (SQLSTATE 42808)。

BEFORE 触发器中的 SQL-procedure-statement 不能:
  • 包含任何 INSERT , DELETE 或 UPDATE 操作,也不调用任何使用 MODISQL DATA 定义的例程 (如果它不是复合 SQL (已编译))。
  • 包含对触发器主题表的任何 DELETE 或 UPDATE 操作,也不调用包含此类操作的任何例程 (如果它是复合 SQL (已编译))。
  • 引用使用 REFRESH IMMEDIATE 定义的具体化查询表 (SQLSTATE 42997)
  • 引用 NEW 转换变量中除标识列以外的生成列 (SQLSTATE 42989)。

注意

  • 向已包含行的表添加触发器不会导致激活任何触发的操作。 因此,如果触发器旨在对表中的数据实施约束,那么现有行可能无法满足这些约束。
  • 如果两个触发器的事件同时发生 (例如,如果它们具有相同的事件,激活时间和主题表) ,那么创建的第一个触发器是第一个要执行的触发器。 如果使用 OR REPLACE 选项来替换先前创建的触发器,那么将更改创建时间,因此可能会影响触发器执行的顺序。
  • 如果在定义触发器后将列添加到主题表,那么以下规则适用:
    • 如果触发器是在没有显式列列表的情况下指定的 UPDATE 触发器,那么对新列的更新将导致触发器激活。
    • 该列将不会在先前定义的任何触发器的触发操作中显示。
    • OLD TABLE 和 NEW TABLE 转换表将不包含此列。 因此,对转换表执行 SELECT * 的结果将不包含添加的列。
  • 如果将列添加到触发式操作中引用的任何表,那么新列将对触发式操作不可见。
  • 如果触发器主体中引用的对象不存在或被标记为无效,或者定义程序暂时没有访问该对象的特权,并且如果数据库配置参数 auto_reval 设置为 DEFERRED_FORCE ,那么仍将成功创建触发器。 触发器将标记为无效,并将在下次调用时重新验证。
  • SQL-procedure-statement 中指定的全查询的结果在触发器内部或外部不可用。
  • 在触发式复合语句中调用的过程不得发出 COMMIT 或 ROLLBACK 语句 (SQLSTATE 42985)。
  • 不支持在搜索型 UPDATE 语句,搜索型 DELETE 语句或 INSERT 语句中包含对昵称的引用的过程 (SQLSTATE 25000)。
  • 表访问限制:: 如果某个过程定义为 READS SQL DATA 或 MODIFIED SQL DATA ,那么该过程中的任何语句都不能访问正在由调用该过程的复合语句修改的表 (SQLSTATE 57053)。 如果该过程定义为 MODIFY SQL DATA ,那么该过程中的任何语句都不能修改正在由调用该过程的复合语句读取或修改的表 (SQLSTATE 57053)。
  • 在级联引用约束循环中涉及的表上定义的 BEFORE DELETE 触发器不应包括对其定义的表的引用,也不应包括在对引用完整性约束循环求值期间通过级联修改的任何其他表。 此类触发器的结果依赖于数据,因此可能无法生成一致的结果。

    In its simplest form, this means that a BEFORE DELETE trigger on a table with a self-referencing referential constraint and a delete rule of CASCADE should not include any references to the table in the 触发操作.

  • 创建触发器会导致某些包被标记为无效:
    • 如果创建了没有显式列列表的 UPDATE 触发器,那么目标表或视图上具有更新用法的包将失效。
    • 如果创建了具有列列表的 UPDATE 触发器,那么仅当该程序包还在 CREATE TRIGGER 语句的 column-name 列表中的至少一个列上具有更新用法时,才会使目标表上具有更新用法的程序包失效。
    • 如果创建了 INSERT 触发器,那么在目标表或视图上具有插入用法的包将失效。
    • 如果创建了删除触发器,那么在目标表或视图上具有删除用途的数据包将失效。
  • 在应用程序显式绑定或重新绑定,或者执行程序包并且数据库管理器自动重新绑定程序包之前,该程序包将保持无效状态。
  • 不可操作触发器: 不可操作触发器 是不再可用的触发器,因此永不激活。 在下列情况下,触发器将变为不可用:
    • 将撤销触发器创建者需要具有的用于执行触发器的特权
    • 删除触发操作所依赖的对象 (例如,表,视图或别名)
    • 触发操作所依赖的视图变得不可用
    • 将删除作为触发器的主题表的别名。

    实际上,不可操作的触发器是由于 DROP 或 REVOKE 语句的级联规则而删除触发器定义的触发器。 例如,删除视图时,任何具有 SQL-procedure-statement 的触发器 (其中包含对该视图的 的引用) 都将不可用。

    当触发器变为不可用时,带有执行激活触发器的操作的语句的所有程序包都将被标记为无效。 当程序包重新绑定 (显式或隐式) 时,将完全忽略不可操作的触发器。 同样,具有执行激活触发器的操作的动态 SQL 语句的应用程序也将完全忽略任何不可操作的触发器。

    仍可以在 DROP TRIGGER 和 COMMENT ON TRIGGER 语句中指定触发器名称。

    可通过使用不可用触发器的定义文本发出 CREATE TRIGGER 语句来重新创建不可用触发器。 此触发器定义文本存储在 SYSCAT.TRIGGERS 目录视图。 请注意,不需要显式删除不可操作的触发器以重新创建该触发器。 发出带有相同 trigger-name 的 CREATE TRIGGER 语句作为不可用触发器将导致该不可用触发器被替换为警告 (SQLSTATE 01595)。

    不可用触发器由 SYSCAT.TRIGGERS 目录视图。

  • 执行触发器时发生的错误: 使用 SQLSTATE 09000 返回在执行触发的 SQL 语句期间发生的错误,除非该错误被视为严重错误。 如果错误严重,那么将返回严重错误 SQLSTATE。 对于非严重错误, SQLCA 的 SQLERRMC 字段将包括触发器名称, SQLCODE , SQLSTATE 以及从故障标记中拟合的标记数。

    SQL-procedure-statement 可以包含 SIGNAL SQLSTATE 语句或 RAISE_ERROR 函数。 在这两种情况下,返回的 SQLSTATE 是 SIGNAL SQLSTATE 语句或 RAISE_ERROR 条件中指定的 SQLSTATE。

  • 使用尚不存在的模式名称创建触发器将导致隐式创建该模式,前提是该语句的授权标识具有 IMPLICIT_SCHEMA 权限。 模式所有者是 SYSIBM。 该模式上的 CREATEIN 特权会授予 PUBLIC。
  • DB2SECURITYLABEL 列: 可以在 BEFORE TRIGGER 的触发器主体中引用 $TAG7 DB2SECURITYLABEL $TAG8 列,但不能在 BEFORE 触发器的主体中对其进行更改 (SQLSTATE 42989)。
  • BUSINESS_TIME 时间段列: 无法在 BEFORE UPDATE 触发器的主体中更改 BUSINESS_TIME 时间段的开始和结束列 (SQLSTATE 42808)。
  • 只读视图: 为视图添加 INSTEAD OF 触发器会影响视图的只读特征。 如果只读视图与 INSTEAD OF 触发器具有依赖关系,那么为 INSTEAD OF 触发器定义的操作类型将定义视图是可删除,可插入还是可更新。
  • 转换变量值和 INSTEAD OF 触发器: 在 INSTEAD OF 触发器中可视的新转换变量或新转换表列的初始值设置如下:
    • 如果为插入操作中的列显式指定了值,那么相应的新转换变量就是显式指定的值。
    • 如果未对插入操作中的列显式指定值或指定 DEFAULT 子句,那么对应的新转换变量为:
      • 底层表列的缺省值 (如果视图列是可更新的 (没有 INSTEAD OF 触发器))
      • 否则,为空值
    在 INSTEAD OF UPDATE 触发器中可视的新转换变量的初始值设置如下:
    • 如果在更新操作中为列显式指定了值,那么相应的新转换变量就是显式指定的值。
    • 如果对更新操作中的列显式指定 DEFAULT 子句,那么对应的新转换变量为:
      • 底层表列的缺省值 (如果视图列是可更新的 (没有 INSTEAD OF 触发器))
      • 否则,为空值
    • 否则,对应的新转换变量是行中列的现有值。
  • 触发器和类型表: 可以将 BEFORE 或 AFTER 触发器附加到表层次结构的任何级别的类型表。 如果 SQL 语句激活多个触发器,那么将按触发器的创建顺序执行触发器,即使触发器连接到类型表层次结构中的不同表也是如此。

    激活触发器时,其转换变量 (OLD , NEW , OLD TABLE 和 NEW TABLE) 可能包含子表行。 但是,它们将仅包含在其附加到的表上定义的列。

    INSERT , UPDATE 和 DELETE 语句的影响:
    • 行触发器: 当 SQL 语句用于 INSERT , UPDATE 或 DELETE 表行时,它会激活附加到包含该行的最特定表以及该表的所有超表的行触发器。 无论 SQL 语句如何访问表,此规则始终为 true。 例如,当发出 UPDATE EMP 命令时,某些更新的行可能位于子表 MGR 中。 对于 EMP 行,将激活附加到 EMP 及其超表的行触发器。 对于 MGR 行,将激活附加到 MGR 及其超表的行触发器。
    • 语句触发器 :INSERT , UPDATE 或 DELETE 语句激活附加到可能受语句影响的表 (及其超表) 的语句触发器。 无论这些表中的任何实际行是否受影响,此规则始终为 true。 例如,在 INSERT INTO EMP 命令上,将激活 EMP 及其超表的语句触发器。 作为另一个示例,在 UPDATE EMP 或 DELETE EMP 命令上,将激活 EMP 及其超表和子表的语句触发器,即使未更新或删除任何子表行也是如此。 同样, UPDATE ONLY (EMP) 或 DELETE ONLY (EMP) 命令将激活 EMP 及其超表的语句触发器,但不激活子表的语句触发器。
    DROP TABLE 语句的影响: DROP TABLE 语句不会激活连接到要删除的表的任何触发器。 但是,如果删除的表是子表,那么会将删除的表的所有行视为从其超表中删除。 因此,对于表 T:
    • 行触发器 :DROP TABLE T 针对 T 的每一行激活附加到 T 的所有超表的行类型删除触发器。
    • 语句触发器 :DROP TABLE T 激活附加到 T 的所有超表的语句类型删除触发器,而不考虑 T 是否包含任何行。
    视图上的操作: 要预测视图上的操作激活的触发器,请使用视图定义将该操作转换为基本表上的操作。 例如:
    1. SQL 语句执行 UPDATE V1,其中 V1 是具有子视图 V2的带类型视图。 假设 V1 具有底层表 T1,而 V2 具有底层表 T2。 该语句可能会影响 T1, T2及其子表中的行,因此会针对 T1 和 T2 及其所有子表和超表激活语句触发器。
    2. SQL 语句执行 UPDATE V1,其中 V1 是具有子视图 V2的带类型视图。 假设 V1 定义为 SELECT ... FROM ONLY (T1) 和 V2 定义为 SELECT ... FROM ONLY (T2)。 由于该语句无法影响 T1 和 T2的子表中的行,因此将对 T1 和 T2 及其超表激活语句触发器,但不会激活其子表。
    3. SQL 语句执行 UPDATE ONLY (V1) ,其中 V1 是定义为 SELECT 的类型视图 ... FROM T1。 该语句可能会影响 T1 及其子表。 因此,将对 T1 及其所有子表和超表激活语句触发器。
    4. SQL 语句执行 UPDATE ONLY (V1) ,其中 V1 是定义为 SELECT 的类型视图 ... FROM ONLY (T1)。 在这种情况下, T1 是可受语句影响的唯一表,即使 V1 具有子视图且 T1 具有子表也是如此。 因此,仅对 T1 及其超表激活语句触发器。
  • MERGE 语句和触发器:MERGE 语句可以执行更新,删除和插入操作。 执行更新,删除或插入操作时,将对 MERGE 语句激活适用的 UPDATE , DELETE 或 INSERT 触发器。
  • 模糊处理:CREATE TRIGGER 语句可以采用模糊处理的形式提交。 在模糊化语句中,只有触发器名称是可读的。 该语句的其余部分以不可读的方式进行编码,但可由数据库服务器进行解码。 可以通过调用 DBMS_DDL.WRAP 函数来生成模糊化的语句。
  • 使用受保护选项创建触发器: 通常,具有 SECADM 权限的用户没有创建数据库对象 (例如触发器或用户定义的函数) 的特权。 通常,他们将检查触发器访问的数据,确保其安全,然后将 CREATE_SECURE_OBJECT 权限授予具有创建安全触发器所需的特权的人员。 创建触发器后,他们将撤销触发器所有者的 CREATE_SECURE_OBJECT 权限。

    触发器被认为是安全的。 数据库管理器将安全属性视为声明用户已为触发器主体中的所有活动建立审计过程的断言。 如果安全触发器引用用户定义的函数,那么数据库管理器将假定这些函数是安全的,而不会进行验证。 如果这些函数可以访问敏感数据,那么具有 SECADM 权限的用户需要确保允许这些函数访问这些数据,并且此审计进程正在复审所有后续 ALTER FUNCTION 语句或对外部包的更改。

    如果触发器的主题表已激活行级别或列级别访问控制,那么触发器必须是安全的。 同样,如果触发器的主题表是视图,并且视图定义中的一个或多个底层表已激活行级别或列级别访问控制,那么触发器必须是安全的。

  • 使用 "不受保护" 选项创建触发器: 如果触发器的主题表已激活行级别或列级别访问控制,那么 CREATE TRIGGER 语句将返回错误。 同样,如果在视图上定义了触发器,并且该视图定义中的一个或多个底层表已激活行级别或列级别访问控制,那么 CREATE TRIGGER 语句将失败。
  • 未对转换变量和转换表实施的行和列访问控制: 触发器用于数据库完整性,因此需要在安全性与数据库完整性之间进行平衡。 如果对主题表或主题视图的底层表激活了行级别或列级别访问控制,那么不会将行许可权和列掩码应用于转换变量和转换表的初始值。 对于触发器主体中引用的转换变量和转换表,或者作为自变量传递给触发器主体中调用的用户定义函数的转换变量和转换表,还会忽略对主题表或主题视图的底层表实施的行级别和列级别访问控制。 要确保触发器操作中的 SQL 语句没有安全问题以访问转换变量和转换表中的敏感数据,必须使用安全选项创建触发器。 如果触发器不安全,那么 CREATE TRIGGER 语句将返回错误。
  • 隐式隐藏列的注意事项: 对于定义为隐式隐藏的任何列,都存在转换变量。 在触发器主体中,可引用与隐式隐藏列对应的转换变量。
  • 重新绑定从属包: 每个已编译的触发器都有一个从属包。 可以随时使用 REBIND_ROUTINE_PACKAGE 过程来重新绑定程序包。 显式地重新绑定从属包不会重新验证无效触发器。 使用自动重新验证或使用 ADMIN_REVALIDATE_DB_OBJECTS 过程显式地重新验证无效触发器。 触发器重新验证会自动重新绑定从属程序包。
  • 语法替代方法: 为了与先前版本的 Db2® 和其他数据库产品兼容,支持以下语法替代方法。 这些备用项是非标准的,不应使用。
    • 可以指定 OLD_TABLE 来代替 OLD TABLE ,也可以指定 NEW_TABLE 来代替 NEW TABLE
    • 可以在 FOR EACH ROW 或 FOR EACH STATEMENT 之后指定 MODE DB2SQL

示例

  • 示例 1: 创建两个触发器,这将导致自动跟踪公司管理的员工数量。 这些触发器将与下列表交互:
    • 具有以下列的 EMPLOYEE 表:ID、NAME、ADDRESS 和 POSITION。
    • 具有以下列的 COMPANY_STATS 表:NBEMP、NBPRODUCT 和 REVENUE。
    每次雇请新的人员时(即,每次在 EMPLOYEE 表中插入新行时),第一个触发器就增加职员数:
       CREATE TRIGGER NEW_HIRED
         AFTER INSERT ON EMPLOYEE
         FOR EACH ROW
         UPDATE COMPANY_STATS SET NBEMP = NBEMP + 1
    每次职员离开公司时(即,每次从 EMPLOYEE 表中删除行时),第二个触发器就减少职员数:
       CREATE TRIGGER FORMER_EMP
         AFTER DELETE ON EMPLOYEE
         FOR EACH ROW
         UPDATE COMPANY_STATS SET NBEMP = NBEMP - 1
  • 示例 2: 创建触发器以确保每当更新部件记录时,都执行以下检查和 (如果需要) 操作:
    • 如果现有量小于最大库存量的 10%,那么发出一个装货请求,要求订购的受影响部件的商品数为最大库存量减去现有量。

    该触发器将与具有以下列的 PARTS 表交互:PARTNO、DESCRIPTION、ON_HAND、MAX_STOCKED 和 PRICE。

    ISSUE_SHIP_REQUEST 是一个用户定义的函数,它将其他部件的定货单发送给适当的公司。
       CREATE TRIGGER REORDER
         AFTER UPDATE OF ON_HAND, MAX_STOCKED ON PARTS
         REFERENCING NEW AS N
         FOR EACH ROW
         WHEN (N.ON_HAND < 0.10 * N.MAX_STOCKED)
         BEGIN ATOMIC
         VALUES(ISSUE_SHIP_REQUEST(N.MAX_STOCKED - N.ON_HAND, N.PARTNO));
         END
  • 示例 3: 重复示例 2 中的方案,但使用全查询而不是 VALUES 语句来调用用户定义的函数。 此示例还显示了如何将触发器定义为语句触发器而不是行触发器。 对于针对 WHERE 子句求值为 true 的转换表中的每一行,将针对部件发出送货请求。
       CREATE TRIGGER REORDER 
          AFTER UPDATE OF ON_HAND, MAX_STOCKED ON PARTS 
          REFERENCING NEW TABLE AS NTABLE
          FOR EACH STATEMENT
             BEGIN ATOMIC 
                SELECT ISSUE_SHIP_REQUEST(MAX_STOCKED - ON_HAND, PARTNO)
                   FROM NTABLE 
                WHERE (ON_HAND < 0.10 * MAX_STOCKED); 
          END
  • 示例 4: 创建一个触发器,当发生将导致工资增长超过当前工资的 10% 的更新时,此触发器将导致错误。
       CREATE TRIGGER RAISE_LIMIT
         AFTER UPDATE OF SALARY ON EMPLOYEE
         REFERENCING NEW AS N OLD AS O
         FOR EACH ROW
         WHEN (N.SALARY > 1.1 * O.SALARY)
                SIGNAL SQLSTATE '75000' SET MESSAGE_TEXT='Salary increase>10%'
  • 示例 5: 考虑用于记录和跟踪股价更改的应用程序。 数据库包含两个表:CURRENTQUOTE 和 QUOTEHISTORY。
       Tables: CURRENTQUOTE (SYMBOL, QUOTE, STATUS)
               QUOTEHISTORY (SYMBOL, QUOTE, QUOTE_TIMESTAMP)
    当 CURRENTQUOTE 的 QUOTE 列更新时,应该将新的报价以及时间戳记复制至 QUOTEHISTORY 表。 还应该更新 CURRENTQUOTE 的 STATUS 列以反映股票是否出现下列情况:
    1. 价值上升;
    2. 创年内新高;
    3. 滴入值;
    4. 创年内新低;
    5. 值稳定。
    实现此功能的 CREATE TRIGGER 语句如下:
    • 设置状态的触发器定义:
         CREATE TRIGGER STOCK_STATUS
           NO CASCADE BEFORE UPDATE OF QUOTE ON CURRENTQUOTE
           REFERENCING NEW AS NEWQUOTE OLD AS OLDQUOTE
           FOR EACH ROW
           BEGIN ATOMIC
              SET NEWQUOTE.STATUS =
                CASE
                   WHEN NEWQUOTE.QUOTE >
                         (SELECT MAX(QUOTE) FROM QUOTEHISTORY
                         WHERE SYMBOL = NEWQUOTE.SYMBOL
                         AND YEAR(QUOTE_TIMESTAMP) = YEAR(CURRENT DATE) )
                      THEN 'High'
                   WHEN NEWQUOTE.QUOTE <
      (SELECT MIN(QUOTE) FROM QUOTEHISTORY
                         WHERE SYMBOL = NEWQUOTE.SYMBOL
                         AND YEAR(QUOTE_TIMESTAMP) = YEAR(CURRENT DATE) )
                      THEN 'Low'
                   WHEN NEWQUOTE.QUOTE > OLDQUOTE.QUOTE
                      THEN 'Rising'
                   WHEN NEWQUOTE.QUOTE < OLDQUOTE.QUOTE
                      THEN 'Dropping'
                   WHEN NEWQUOTE.QUOTE = OLDQUOTE.QUOTE
                      THEN 'Steady'
                END;
           END
    • 记录 QUOTEHISTORY 表中的变动的触发器定义:
         CREATE TRIGGER RECORD_HISTORY
           AFTER UPDATE OF QUOTE ON CURRENTQUOTE
           REFERENCING NEW AS NEWQUOTE
           FOR EACH ROW
           BEGIN ATOMIC
             INSERT INTO QUOTEHISTORY
               VALUES (NEWQUOTE.SYMBOL, NEWQUOTE.QUOTE, CURRENT TIMESTAMP);
           END
  • 示例 6:创建用于覆盖组织表中员工记录中位置字段的任何更改的触发器。 如果处理了购买较小公司时获取的新员工记录,并且分配给该员工的目标位置是 多伦多 ,而新的目标位置是 洛杉矶,那么此触发器将非常有用。 前触发器将确保无论应用程序为此字段分配什么值,最终生成的值都是 Los Angeles
    
       CREATE TRIGGER LOCATION_TRIGGER
         NO CASCADE
          BEFORE UPDATE ON ORG
          REFERENCING
            OLD AS PRE
            NEW AS POST
          FOR EACH ROW
          WHEN (POST.LOCATION = 'Toronto')
             SET POST.LOCATION = 'Los Angeles';
          END
    
  • 示例 7: 创建 BEFORE 触发器,该触发器在将包含新产品描述的 XML 文档插入到 SAMPLE 数据库的 PRODUCT 表之前自动验证这些文档:
    
       CREATE TRIGGER NEWPROD NO CASCADE BEFORE INSERT ON PRODUCT
          REFERENCING NEW AS N
          FOR EACH ROW
          BEGIN ATOMIC
             SET (N.DESCRIPTION) = XMLVALIDATE(N.DESCRIPTION
                ACCORDING TO XMLSCHEMA ID product);
          END
    
  • 示例 8: 创建用于跟踪公司管理的员工数量和工资的多事件触发器。 触发器将与以下列和表进行交互:
    • EMPLOYEE 表中的 ID , NAME , ADDRESS , SALARY 和 POSITION 列
    • COMPANY_STATS 表中的 NBEMP , NBPRODUCT 和收入列
    该触发器会在每次雇佣新员工时增加员工数量; 在每次员工离开公司时减少员工数量,并在发生会导致工资增长超过当前工资的 10% 的更新时产生错误:
    CREATE OR REPLACE TRIGGER HIRED
       AFTER INSERT OR DELETE OR UPDATE OF SALARY ON EMPLOYEE
       REFERENCING NEW AS N OLD AS O FOR EACH ROW
       BEGIN
          IF INSERTING THEN UPDATE COMPANY_STATS SET NBEMP = NBEMP + 1;
          ELSEIF DELETING THEN UPDATE COMPANY_STATS SET NBEMP = NBEMP - 1;
          ELSEIF (UPDATING AND (N.SALARY > 1.1 * O.SALARY))
             THEN SIGNAL SQLSTATE '75000' SET MESSAGE_TEXT='Salary increase>10%';
          END IF;
       END;
  • 示例 9: 创建触发器以确保在更新部件记录之前执行以下检查和 (如果需要) 操作:
    • 如果现有数量小于最大库存数量的 10% ,请将新订单记录放入 ORDER 表中,并发出送货请求,以订购受影响部件的项目数量,使其等于最大库存数量减去现有数量。
    触发器与以下列和表进行交互:
    • PARTS 表中的 PARTNO , DESCRIPTION , ON_HAND ,MAX_袜和 PRICE 列
    • ORDER 表中的 PARTNO 和 PRICE 列
    ISSUE_SHIP_REQUEST 是用户定义的 SQL 数据修改存储过程,用于向供应公司发送其他部件的订单表单,并在供应公司确认订单表单后从 ORDER 表中删除相应行。
    CREATE TRIGGER REORDER
       BEFORE UPDATE OF ON_HAND, MAX_STOCKED ON PARTS
       REFERENCING NEW AS N
       FOR EACH ROW
       WHEN (N.ON_HAND < 0.10 * N.MAX_STOCKED)
       BEGIN
          INSERT INTO ORDERS VALUES (N.MAX_STOCKED - N.ON_HAND, N.PARTNO);
          CALL ISSUE_SHIP_REQUEST(N.MAX_STOCKED - N.ON_HAND, N.PARTNO);
       END;