用户定义的数据典范、并发性思考成分等等
触发器
什么是触发器?
触发器(trigger) 是一个针对表定义的数据库对象,在这个表中拔出、更新或删除行时会激活它。触发器本身包括用 DB2 的内联 SQL Procedural Language(SQL PL)编写的进程式逻辑,这些逻辑将在触发器被激活时执行。触发器可以用于各类用处,包括数据查验、施行援用完整性束缚、审计和其他变乱驱动的操作。也可以针对视图定义触发器 —— 它们称为 INSTEAD OF
触发器。INSTEAD OF
触发器与针对表定义的触发器的差异在于,它会执行触发器逻辑,而不执行激活它的语句。比如,假如由于对一个视图执行 INSERT
语句而激活 INSTEAD OF
触发器,那么拔出操作理论上不会执行;相反,触发器逻辑会决意执行哪些操作。对于针对表定义的触发器,招致触发的语句和 触发器逻辑城市执行。
当定义触发器的表上爆发指定的数据批改操作时,触发器就会激活。可以在同一个表上定义多个触发器,可以针对异样的数据批改操作,也可以针对分比如的操作。触发器按照创立它们的按次激活。比如,假定触发器 A 和触发器 B 都定义为在更新表 Q 中的行时激活,假如触发器 A 是先创立的,那么它在触发器 B 之前激活。触发器还可以激活其他触发器 —— 这种现象称为触发器层叠(trigger cascading)。最多支撑 16 级触发器层叠。
回页首
触发器激活时辰和粒度
除了指定激活触发器的变乱典范(INSERT
、UPDATE
或 DELETE
)之外,还必须指定何时 应该激活触发器和触发器的粒度(granularity)。有两个用于指定触发器激活时辰的选项:BEFORE
和 AFTER
。
BEFORE
:触发器在招致触发的语句休止数据批改之前激活和运转。这个体例会阻止这个触发器逻辑的执行激活其他触发器。AFTER
:这指定触发器逻辑在招致触发的语句休止数据批改之后运转。
正如下面的定义中提到的,BEFORE
触发器不克不及包括激活其他触发器的任何操作。因而,在这种触发器中不支撑 INSERT
、UPDATE
和 DELETE
语句。另一方面,AFTER
触发器中的逻辑可以激活其他触发器;因而容许下面这些数据批改操作。
还必须指定触发器的粒度,粒度决意触发器逻辑应该在招致触发的语句影响每一行之后执行,还是在影响一切行之后只执行一次。两个选项是 FOR EACH STATEMENT
和 FOR EACH ROW
。
FOR EACH STATEMENT
:指定触发器逻辑只在招致触发的语句措置惩一切受影响的行之后操作一次。不克不及对BEFORE
触发器或INSTEAD OF
触发器指定这种触发器粒度。FOR EACH ROW
:指定触发器逻辑在招致触发的语句影响表或视图中的每一行之后操作一次。
无论以什么按次创立,BEFORE
触发器总是在 AFTER
触发器之前激活。
回页首
触发器语法
既然曾经相识了触发器的基本常识,就来看看触发器语法和几个示例。清单 2 给出 CREATE TRIGGER
的语法图。垂青,在语法图的底部是触发器中容许运用的 SQL 进程式语句列表。一定要记着,触发器运用的进程式措辞(内联 SQL PL)理论上是 DB2 SQL PL 的子集,这意味着在 SQL 存储进程中容许运用的某些语句在触发器中是不容许运用的。
清单 2. 触发器语法图
.-NO CASCADE-. >>-CREATE TRIGGER--trigger-name-- - ------------ --BEFORE- -----> -AFTER------------------ '-INSTEAD OF-------------' >-- -INSERT-------------------------- --ON-- -table-name- ------> -DELETE-------------------------- '-view-name--' '-UPDATE-- --------------------- -' | .-,-----------. | | V | | '-OF----column-name- -' >-- ------------------------------------------------------------------ --> | .-------------------------------------------------. | | V (1) (2) .-AS-. | | '-REFERENCING------------------ -OLD-- ---- --correlation-name- - -' | .-AS-. | -NEW-- ---- --correlation-name- | .-AS-. | -OLD TABLE-- ---- --identifier- | .-AS-. | '-NEW TABLE-- ---- --identifier-' >-- -FOR EACH ROW-------------- --| triggered-action |--------->< | (3) | '--------FOR EACH STATEMENT-' triggered-action: |-- ------------------------------------- ----------------------> | (4) | '--------WHEN--(--search-condition--)-' >-- -------- --| SQL-procedure-statement |----------------------| '-label:-' SQL-procedure-statement: |-- -CALL---------------------------------------------- --------| -Compound SQL (Dynamic)---------------------------- -FOR----------------------------------------------- - ----------------------------------- --fullselect- | | .-,-----------------------. | | | | V | | | | '-WITH----common-table-expression- -' | -GET DIAGNOSTICS----------------------------------- -IF------------------------------------------------ -INSERT-------------------------------------------- -ITERATE------------------------------------------- -LEAVE--------------------------------------------- -MERGE--------------------------------------------- -searched-delete----------------------------------- -searched-update----------------------------------- -SET Variable-------------------------------------- -SIGNAL-------------------------------------------- '-WHILE---------------------------------------------'
我们来看一个非常简朴的 UPDATE
触发器示例。清单 3 给出这个触发器的代码。
清单 3. 一个简朴的 UPDATE 触发器
CREATE TRIGGER audit_emp AFTER UPDATE ON employee FOR EACH ROW INSERT INTO audit_employee VALUES (current timestamp, current user)
当在 EMPLOYEE 表中更新行时,就会激活这个触发器。这个触发器定义为 AFTER
触发器,这意味着它在完成 UPDATE
操作之后 激活。别的,由于这个触发器定义为 FOR EACH ROW
,它的逻辑将在更新受影响的每一行之后执行。比如,假如 EMPLOYEE 表中有 100 个纪录遭到 UPDATE
语句的影响,那么我们可以预期在 AUDIT_EMPLOYEE 表中会拔出 100 个新行。可是,假如这个触发器定义为 FOR EACH STATEMENT
,那么 AUDIT_EMPLOYEE 表中只会增加一行,由于触发器逻辑只在 UPDATE
语句措置惩一切行之后执行一次。
今朝看一个更庞大的示例。清单 4 给出一个雷同的触发器 AUDIT_EMP2。这个触发器运用比前一个示例更初级的语法。
清单 4. 另一个 UPDATE 触发器
CREATE TRIGGER audit_emp2 AFTER UPDATE OF salary ON employee REFERENCING NEW AS n OLD AS o FOR EACH ROW WHEN (N.SALARY > 1.1 * O.SALARY) INSERT INTO audit_employee VALUES (current timestamp, current user)
这个示例与前一个示例雷同,可是包括更庞大的语法。第一段新语法是 UPDATE OF <column_name>
子句。它可以对激活触发器的情形休止限定,让触发器只在更新一个或多个特定列时激活。在后面的示例中,更新 EMPLOYEE 表中的任何列时城市激活触发器。在这个示例中,只在更新 SALARY 列时激活触发器。
另一段新语法是 REFERENCING NEW AS n OLD AS o
子句。这个子句容许设置转换变量(transition variable),可以经由进程这个表访谒旧的列值(UPDATE
操作之前的值)和新的列值(UPDATE
之后的值)。定义了转换变量之后,可以运用它们援用新列值和旧列值 —— 比如,N.SALARY 和 O.SALARY。并非每种数据批改操作都能同时定义 NEW
和 OLD
转换变量。比如,在 INSERT
触发器中定义 OLD
转换变量,大概在 DELETE
触发器中定义 NEW
转换变量,是没成心义的。
末端一段新语法是 WHEN
子句,它也对激活触发器的前提休止限定。在这个示例中,只在新的薪水值比现有薪水值高 10% 以上时激活触发器。最佳理论是尽可以运用 WHEN
和 UPDATE OF <column_name>
子句限定触发器的激活。假如在不用要的时分激活多个庞大的触发器,就会招致机能损失。
今朝看一个 BEFORE
触发器示例。清单 5 显露一个简朴的 BEFORE
触发器 VALIDATE_INFO。
清单 5. 一个简朴的 BEFORE 触发器
CREATE TRIGGER validate_info NO CASCADE BEFORE INSERT ON payroll REFERENCING NEW AS n FOR EACH ROW BEGIN ATOMIC IF (n.ts1 IS NULL) THEN SET n.ts1 = CURRENT TIMESTAMP; END IF; IF (n.deptcode IS NULL) THEN SET n.deptcode = 'A000'; END IF; END
这是一个典范的 BEFORE INSERT
触发器示例,它在拔出任何数据之前执行数据查验。在这个示例中,搜检能否在 PAYROLL 表的 TS1 和 DEPTCODE 列中拔出了 NULL 值。为这两列提供的 NULL 值会被替换为分比如的默许值。这个触发器阐明的另一个紧急标题后果是,若何在一个触发器中组合多个进程式逻辑语句(即以分号末端的语句)。为了在触发器中运用多个语句,必须将它们包围在一个原子复合块(BEGIN ATOMIC
...END
)中。
版权声明:
原创作品,容许转载,转载时请务必以超链接体例标明文章 原始来由 、作者信息和本声明。否则将究查法律责任。