触发器是对应用动作的响应机制,当应用对一个对象发起 DML 操作时,就会产生一个触发事件(Event)。如果该对象上拥有该事件对应的触发器,那么就会检查触发器的触发条件(Condition)是否满足,如果满足触发条件,那么就会执行触发动作(Action)。
-
事件:触发器的触发事件,当对一个对象执行 UPDATE/DELETE/INSERT 等操作的时候,会激活触发器检查触发条件。
-
条件:触发条件可以是一个表达式或者是一个 SQL 查询语句,当触发条件的执行结果是 FALSE、NULL 或者空集的时候,代表触发条件不满足,触发器不会被触发。
-
动作:触发动作和存储过程相似,它的执行结合了触发器本身的特点,比如可以直接使用触发条件中的执行结果,或者是执行事件修改的元组中的值。
通过 CREATE TRIGGER 命令可以创建一个触发器,在 CREATE TRIGGER 命令中可以指定触发器的事件、条件和动作。
创建触发器具体语句如下:
CREATE [ CONSTRAINT ] TRIGGER trigger_name { BEFORE | AFTER | INSTEAD OF } { event [ OR '...'] }
ON table_name
[ FROM referenced_table_name ]
{ NOT DEFERRABLE | [ DEFERRABLE ] { INITIALLY IMMEDIATE | INITIALLY DEFERRED } }
[ FOR [ EACH ] { ROW | STATEMENT } ]
[ WHEN ( condition ) ]
EXECUTE PROCEDURE function_name ( arguments );
触发事件满足时,还需要考虑触发器的执行时机,触发器语法中提供了两个触发时机:BEFORE 和 AFTER。顾名思义,BEFORE 就是在触发器事件执行之前检查触 发条件以及执行触发动作,而 AFTER 则是在触发事件之后检查触发条件以及执行触发动作。
在 UPDATE 事件发生之前执行触发器,具体语句如下:
CREATE TRIGGER before_update
BEFORE UPDATE
ON ...
在 INSERT 事件发生之后执行触发器,具体语句如下:
CREATE TRIGGER after_insert
AFTER INSERT
ON ...
触发器可以对应到元组(一个 SQL 语句可以更新多个元组),也可以对应到 SQL 语句级,默认是 SQL 语句级。
针对 SQL 语句级的触发器,具体语句如下:
CREATE TRIGGER after_insert
AFTER INSERT
ON warehouse
FOR EACH STATEMENT
...
针对元组级的触发器,具体语句如下:
CREATE TRIGGER after_insert
AFTER INSERT
ON warehouse
FOR EACH ROW
...
针对触发对象的触发事件一旦发生,就会激活触发器,触发器首先会检查触发条件,只有在满足触发条件的情况下,才会被真正地执行。其中元组级的触发器可以将更新前后的值嵌入到触发器的触发条件中。
-
NEW.column_name:UPDATE 或 INSERT 事件对应“新”元组,column_name 对应新元组上的对应的列值
-
OLD.column_name:UPDATE 或 DELETE 事件对应“老”元组,column_name 对应老元组上的列值
触发条件中包含 NEW 元组对应的列值。具体语句如下:
CREATE TRIGGER after_insert
AFTER INSERT
ON warehouse
FOR EACH ROW
WHEN (NEW.w_id>10)
...
触发器的动作主要是执行一个函数,在创建触发器之前,需要创建一个函数,如果返回值是 Trigger,那么该函数就是触发器函数,否则是普通函数。同一个触发器可以指定多个触发事件,每个事件发生时都能激活触发器来执行触发器的动作。
在 warehouse 表上创建一个完整的触发器,触发器的工作是在 wh_log 表中记录 DELETE/UPDATE/INSERT 操作的具体信息,实现语句如下:
CREATE TABLE wh_log
(
event VARCHAR(10),
time_stamp TIMESTAMP,
w_id SMALLINT,
w_name VARCHAR(10)
);
CREATE 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;
ELSEIF (TG_OP ='UPDATE') THEN
INSERT INTO wh_log SELECT 'U', now(), NEW.w_id, NEW.w_name;
RETURN NEW;
ELSEIF (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 TRIGGER 命令。
DROP TRIGGER warehouse_log;