代码改变世界

SQL触发器的一点心得

2010-12-02 09:47  bingcaihuang  阅读(783)  评论(0编辑  收藏  举报

触发器(Trigger)是用户定义在关系表上的一类由事件驱动的特殊过程。一旦定义,任何用户对表的增、删、改操作均由服务器自动激活相应的触发器。它类似于约束,但是比约束更加灵活,并且可以实施比FOREIGN KEY(外键)约束、CHECK约束更为复杂的检查和操作,具有更精细和更强大的数据控制能力。


下面是触发器一些特性:


1、 表的创建者才可以在表上创建触发器,并且一个表上只能创建一定数量的触发器;


2、 触发器名可以包含模式名,也可以不包含。但是在同一模式下,触发器必须是唯一的,并且触发器名和表名必须在同一模式下;


3、 当某个表的数据发生变化时,将激活定义在该表上相应的“触发事件”的触发器,因此,该表也称为触发器的目标表;


4、 触发事件可以是单独的操作(增、删、改)或几个操作的组合,如INSERT OR DELETE等。而且UPDATE后边还可以有OF<触发列,…..>,即进一步指明修改哪些列时激活触发器;


5、 触发器的类型,按所触发动作的间隔尺寸可以分为行级触发器(FOR EACH ROW)和语句级触发器(FOR EACH STATEMENT)。对于什么叫“间隔尺寸”,书面上比较难理解,那么看以下的例子:

例:假设有个职工工资表WORKER,要求每个职工的应发工资不能低于3000元。那么如果在这个表上创建了一个AFTER UPDATE触发器,且该表有1000行记录,执行如下语句:

UPDATE WORKER SET Deptno=5;


如果改触发器为语句级触发器,那么执行完该语句后,触发动作只发生一次。如果是行级触发器,触发动作将执行将执行1000次;


6、 触发条件,当触发器被激活时,只有当触发条件为真时触发动作体才执行。如果省略WHEN触发条件,则触发动作体在触发器被激活后无条件执行;


7、 触发动作体既可以是一个匿名PL/SQL过程块,也可以是对已创建存储过程的调用。如果是行级触发器,在两种情况下,用户都能在过程体中使用NEW和OLD引用UPDATE/INSERT事件之后的新值和UPDATE/INSERT事件之后的旧值。如果是语句级触发器,则不能在触发动作体中使用NEW或OLD进行引用。

如果触发动作体执行失败,激活触发器的事件就会终止执行,触发器的目标表或触发器可能影响的其他对象不会发生任何变化。

以下是两个个经典的触发器例子:


例1:定义一个BEFORE行级触发器,为职工表WORKER定义完整性规则“管理人员工资不能低于4000元,如果低于4000元,自动改为4000元”。


CREATE TRIGGER insert_Or_Updatee_Sal /*在WORKER表中定义触发器*/
BEFORE INSERT OR UPDATE ON WORKER /* 触发事件是插入或更新操作*/
FOR EACH ROW /*表示行级触发器*/
AS BEGIN /*定义触发器动作体,这是一个PL/SQL过程块*/
IF(new.Job=’管理人员’)AND(new.Sal<4000)THEN /*因为是行级触发器*/
new.Sal := 4000; /*过程体中使用插入或更新操作后的新值*/
END IF;
END;

例2:定AFFTER行级触发器,当员工表WORKER的工资发生变化后就自动在工资变化表Sal_log中增加一条记录。


首先建立工资变化表Sal_log:
CREATE TABLE Sal_log
(Eno NUMERIC(4) REFERENCES WORKER(Eno),
Sal NUMERIC(7,2),
Username char(10),
Date TIMESTAMP
);

CREATE TRIGGER Insert _Sal
AFTER INSERT ON WOEKER
FOR EACH ROW
AS BEGIN
INSERT INTO Sal_log VALUES(
new.Eno,new.Sal,CURRENT_USER,CURRENT_TIMESTAMP);
END;

CREATE TRIGGER Update _Sal
AFTER INSERT ON WOEKER
FOR EACH ROW
AS BEGIN
IF(new.Sal<>old.Sal) THEN INSERT INTO Sal_log VALUES(
new.Eno,new.Sal,CURRENT_USER,CURRENT_TIMESTAMP);
END IF;
END;