触发器是对应用动作的响应机制,当应用对一个对象发起DML操作时,就会产生一个触发事件(Event),如果该对象上拥有该事件对应的触发器,那么就会检查触发器的触发条件(Condition)是否满足,如果满足触发条件,那么就会执行触发动作(Action),如表2-13所示。
表2-13 触发器说明
名称 | 描述 |
事件 | 触发器的触发事件,当对一个对象执行UPDATE/DELETE/INSERT等操作的时候,会激活触发器检查触发条件 |
条件 | 触发条件可以是一个表达式或者是一个SQL查询语句,当触发条件的执行结果是FALSE、NULL或者空集的时候代表触发条件不满足,触发器不会被触发 |
动作 | 触发的动作和存储过程相似,它的执行结合了触发器本身的特点,比如可以直接使用触发条件中的执行结果,或者是执行事件修改的元组中的值 |
创建一个触发器通过CREATE TRIGGER命令来实现,在CREATE TRIGGER命令中可以指定触发器的事件、条件和动作。
例2-59:将存储过程替换为按照地区分组的数量统计,具体语句如下:
CREATE TRIGGER <trigger name> --触发器名称
<trigger action time> <trigger event>--触发器事件
ON <table name> --触发器对象
[ REFERENCING <old or new values alias list> ] --触发器条件
<triggered action> --触发器动作
触发事件满足时,还需要考虑触发器的执行时机,触发器语法中提供了两个触发时机:BEFORE和AFTER。顾名思义,BEFORE就是在触发器事件执行之前检查触发条件以及执行触发动作,而AFTER则是在触发事件之后检查触发条件以及执行触发动作。
例2-60:在UPDATE事件发生之前执行触发器,具体语句如下:
CREATE TRIGGER before_update
BEFORE UPDATE
ON ……
例2-61:在INSERT事件发生之后执行触发器,具体语句如下:
CREATE TRIGGER after_insert
AFTER INSERT
ON ……
触发器可以对应到元组(一个SQL语句可以更新多个元组),也可以对应到SQL语句级,默认是SQL语句级。
例2-62:针对SQL语句级的触发器,具体语句如下:
CREATE TRIGGER after_insert
AFTER INSERT
ON warehouse
FOR EACH STATEMENT
……
例2-63:针对元组级的触发器,具体语句如下:
CREATE TRIGGER after_insert
AFTER INSERT
ON warehouse
FOR EACH ROW
……
针对触发对象的触发事件一旦发生,就会激活触发器,触发器首先会检查触发条件,只有满足触发条件的情况下,才会真正的执行触发器。其中,元组级的触发器可以将更新前后的值嵌入到触发器的触发条件中,如表2-14所示。
表2-14 “新”“老”元组值触发条件说明
名称 | 描述 |
NEW.column_name | UPDATE或INSERT事件对应“新”元组,column_name对应新元组上的对应的列值 |
OLD.column_name | UPDATE或DELETE事件对应“老”元组,column_name对应老元组上的列值 |
例2-64:触发条件中包含NEW元组对应的列值,具体语句如下:
CREATE TRIGGER after_insert
AFTER INSERT
ON warehouse
FOR EACH ROW
WHEN (NEW.w_id > 10)
……
触发器的动作主要是执行一个函数,在创建触发器之前,需要创建一个函数,如果返回值是Trigger,那么该函数就是触发器函数,否则是普通函数。
同一个触发器可以指定多个触发事件,每个事件发生时都能激活触发器来执行触发器的动作。
例2-65:在warehouse表上创建一个完整的触发器,触发器的工作是在wh_log表中记录DELETE/UPDATE/INSERT操作的具体信息,实现的语句如下:
CREATE TABLE wh_log
(
event VARCHAR(10),
time_stamp TIMESTAMP,
w_id SMALLINT,
w_name VARCHAR(10)
);
CREATE OR REPLACE FUNCTION record_warehouse_log()
RETURNS TRIGGER AS $warehouse_log$
BEGIN
IF (TG_OP = 'DELETE') THEN
INSERT INTO wh_log SELECT 'D', now(), OLD.w_id, OLD.w_name;
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO wh_log SELECT 'U', now(), NEW.w_id, NEW.w_name;
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO wh_log SELECT 'I', now(), NEW.w_id, NEW.w_name;
RETURN NEW;
END IF;
RETURN NULL;
END;
$warehouse_log$ LANGUAGE plpgsql;
CREATE TRIGGER warehouse_log
AFTER INSERT OR UPDATE OR DELETE ON warehouse
FOR EACH ROW EXECUTE PROCEDURE record_warehouse_log();
如果需要删除触发器,可以使用SQL语言中的DROP TIGGER命令。
例2-66:删除触发器,具体语句如下:
DROP TRIGGER warehouse_log;