在DB2中使用SQL过程语言来操作触发器
Update 触发器
除了对 Update 触发器中新数据和现有数据的引用可以被访问之外,Update 触发器和 Insert 触发器十分相似。根据前面的业务规则,我们希望使用触发器来定义有效的状态转换并在所有应用程序中实施。
有效状态转换:
PENDING -> SHIPPED -> DELIVERED -> COMPLETED
PENDING -> CANCELLED
下面的触发器可用来实施这些转换:
1 : CREATE TRIGGER verify_state
2 : NO CASCADE BEFORE UPDATE ON orders_t
3 : REFERENCING OLD AS o NEW AS n
4 : FOR EACH ROW MODE DB2SQL
5 : BEGIN ATOMIC
6 :IF o.status='PENDING' and n.status IN ('SHIPPED','CANCELLED') THEN
7 :-- valid state
8 :ELSEIF o.status='SHIPPED' and
9 :n.status ='DELIVERED' THEN
10:-- valid state
11:ELSEIF o.status='DELIVERED' and
12:n.status = 'COMPLETED' THEN
13:-- valid state
14:ELSE
15:SIGNAL SQLSTATE '80001' ('Invalid State Transition');
16:END IF;
17: END
本例中,触发器名为 verify_state。它是在对表 orders_t 进行更新之前被激活的。另一个不同就是我们用 o 和 n 作为列名限定符分别引用旧值和新值。
第 5 行到第 16 行中的这种状态转换方式是直接的。如果转换没有执行,我们则假定有错误并引发一个应用程序错误,发出消息“Invalid State Transition”。操作将被拒绝。当然,判断逻辑也可写成如下形式:
IF NOT((o.status='PENDING' and n.status IN ('SHIPPED','CANCELLED')) OR
(o.status='SHIPPED' and n.status = 'DELIVERED' OR
(o.status='DELIVERED' and n.status = 'COMPLETED')) THEN
SIGNAL SQLSTATE '80001' ('Invalid State Transition')
END IF;
...前面的写法是为了意思更清晰并能充分说明 IF/THEN/ELSE 结构的句法。
Delete 触发器
对于最后一条业务规则,我们将说明触发器的更简单形式,这在 DB2 UDB 7.2 之前就已经可用了。先将业务规则分为以下两部分:
3a)“如果订单没有被取消就不能被删除。”
3b)“记录已删除的订单信息以备审计。”
下面是实施 3a 的触发器:
1 : CREATE TRIGGER restrict_delete
2 : NO CASCADE BEFORE DELETE ON orders_t
3 : REFERENCING OLD AS o
4 : FOR EACH ROW MODE DB2SQL
5 : WHEN (o.status <> 'CANCELLED')
6 :SIGNAL SQLSTATE '80003' ('Cannot Delete an order that has not been cancelled')
“AFTER” 触发器
对于规则 3b,我们将用一个 AFTER 触发器来记录表orders_t中的删除操作。
1 : CREATE TRIGGER log_delete
2 : AFTER DELETE ON orders_t
3 : REFERENCING OLD AS o
4 : FOR EACH ROW MODE DB2SQL
5 :INSERT INTO delete_log_t VALUES (
'rder #?|| CHAR (o.order_id) ||
'as deleted on ?|| CHAR(CURRENT TIMESTAMP));
该 delete 触发器和前面两个触发器的不同之处在于,这里没有用到 BEGIN ATOMIC 和 END。因为如果在触发器中只有一条 SQL 语句,就不是必需的。上面这个触发器显然没有记录太多有用的信息来支持审计,但演示了如何通过触发器使对一个表的插入操作来触发完成对另一个表的插入。任何时候执行删除操作且满足WHEN 子句中的条件都将激活该触发器。如果你将 WHEN 子句完全删掉(“AFTER”触发器上面),该触发器将一直处于激活状态。
