触发器
触发器是一种特殊存储过程,它不能被直接的调用,而是当同表或视图相关联指定的事件发生时被执行,触发器是特定于一个且只有一个关系(表或视图)和一个阶段的时间事件(BEFORE或AFTER)。它可以指定为一个特定的执行事件(插入、更新、删除)或一些组合两个或三个事件。
另一种已知的触发器形式是作为“数据库触发器”-在一个用户的开始或结束会话(连接)或一个用户事务可以指定触发关联。
作用: 创建一个新的触发器
用于: DSQL, ESQL
语法:
CREATE TRIGGER trigname {
|
|
}
AS
[]
BEGIN
[]
END
::=
FOR {tablename | viewname}
[ACTIVE | INACTIVE]
{BEFORE | AFTER}
[POSITION number]
::=
[ACTIVE | INACTIVE]
{BEFORE | AFTER}
[POSITION number]
ON {tablename | viewname
::=
[ACTIVE | INACTIVE] ON db_event [POSITION number]
::=
[OR [OR ]]
::= { INSERT | UPDATE | DELETE }
::= {
CONNECT |
DISCONNECT |
T RANSACTION START |
TRANSACTION COMMIT |
TRANSACTION ROLLBACK
}
::= { | };
[{ | }; …]
表 5.21. CREATE TRIGGER语句参数
参数 | 描述 |
trigname达 31 个字符组成的触发器名称。所有触发器名称在数据库中它必须是唯一的。 | |
relation_trigger_legacy | 旧式风格的关联触发器的触发声明 |
relation_trigger_sql2003 | 关联触发器声明符合 SQL:2003 标准 |
database_trigger | 数据库触发器声明 |
tablename | 同触发器相关联的表的名称 |
viewname | 同触发器相关联的视图的名称 |
mutation_list | 列表的关系 (表 | 视图) 事件 |
number | 触发器在触发顺序中的位置。从 0 到 32767 |
db_event | 连接或事务事件 |
declarations | 声明本地变量和命名游标部分 |
declare_var | 局部变量声明 |
declare_cursor | 命名游标声明 |
PSQL_statements | 在Firebird数据库编程语言中的语句 (PSQL) |
CREATE TRIGGER语句用于创建一个新的触发器,可以创建触发器为一种关系(表 | 视图)事件(或事件的组合),或为数据库事件。
CREATE TRIGGER以及同它相关的ALTER TRIGGER、 CREATE OR ALTER TRIGGER和RECREATE TRIGGER是一组复合语句,由头和主体组成。消息头指定触发器的名称,关联的名称(为一个关联触发),它适用于触发和事件的阶段。
主体包含可选的局部变量的声明和命名游标后跟随一个或多个语句,或语句块,所有封闭的外块,以关键字BEGIN和 END关键字结束。声明和嵌入语句用分号(;)结束。
触发器的名称必须是唯一的在所有触发器的名称中。
语句结束符
一些 SQL 语句编辑器 — — Firebird专门配备的isql 实用工具和一些第三方的编辑器 — — 使用其内部的约定,要求所有语句都以分号结束。
在这些环境中编码时, 这将同PSQL语法产生一个冲突。如果你不知道这个问题及其解决方案,请详细信息学习PSQL 章中题为 在isql中切换结束符号一节。
关联触发器(对表或视图)
关联触发器被执行在行(记录)级,当每次行的影像被改时被执行.一个触器要么是活跃的,要么是不活跃的。仅活跃的触发器被执行。触发器被创建时默认为活跃(ACTIVE)。
声明形式
Firebird数据库关联触发器支持两种形式的声明:
• 原始的、遗留的语法
• SQL:2003标准兼容形式(推荐)
SQL:2003标准兼容的形式是推荐的一种。
一个关联触发器指定 — — 除其他事项外 — — 一个阶段和一个或多个事件。
阶段
阶段涉及一行数据中的更改的状态事件触发的时间:
•一个BEFORE触发器在指定的数据库操作(插入、 更新或删除)进行之前被触发
•一个AFTERE触发器在数据库操作完成之后被触发
行事件
一个关联触发器定义指定至少一个 DML 操作INSERT、 UPDATE和DELETE以表示一个或多个事件触发器应触发。如果指定了多个操作,则它们必须由关键字OR分隔。没有操作可能会出现一次以上。
在语句块中,可以使用布尔上下文变量INSERTING, UPDATING和DELETING测试当前正在执行的操作。
触发器触发顺序
关键字POSITION允许可选执行顺序 ("触发顺序"), 为一系列的触发器有相同的阶段和事件指定执行顺序作为它们的目标。默认位置为 0。如果指定没有位置,或者几个触发器有单一位置编号,触发器将按名称字母的顺序执行它们。
变量声明
在触发器头部关键字AS下面的可选声明部分是用于定义触发器的局部变量和命名游标。更多详细信息,请参见声明变量和声明游标在程序的 SQL 章。
触发器主体
局部的声明(如果有)是触发器的头部的最后一部分。触发器的主体随后,在那里一个或多个块的 PSQL 语句封闭在关键字开始BEGIN和
以END关键字结束的结构中。
仅视图或表的所有者和管理员拥有使用CREATE TRIGGER的权限
表和视图 CREATE TRIGGER的例子 ︰
1.使用"遗留"的形式建立一个触发器,在插入一条新到记录到CUSTOMER表事件发生前触发。
CREATE TRIGGER SET_CUST_NO FOR CUSTOMER
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.CUST_NO IS NULL) THEN
NEW.CUST_NO = GEN_ID(CUST_NO_GEN, 1);
END
2. 使用SQL:2003标准兼容的形式建立一个触发器,在插入一条新到记录到CUSTOMER表事件发生前触发。
CREATE TRIGGER set_cust_no
ACTIVE BEFORE INSERT POSITION 0 ON customer
AS
BEGIN
IF (NEW.cust_no IS NULL) THEN
NEW.cust_no = GEN_ID(cust_no_gen, 1);
END
3.建立一个触发器,当在CUSTOMER表插入、更新或删除一条记录后触发
CREATE TRIGGER TR_CUST_LOG
ACTIVE AFTER INSERT OR UPDATE OR DELETE POSITION 10
ON CUSTOMER
AS
BEGIN
INSERT INTO CHANGE_LOG (LOG_ID,
ID_TABLE,
TABLE_NAME,
MUTATION)
VALUES (NEXT VALUE FOR SEQ_CHANGE_LOG,
OLD.CUST_NO,
'CUSTOMER',
CASE
WHEN INSERTING THEN 'INSERT'
WHEN UPDATING THEN 'UPDATE'
WHEN DELETING THEN 'DELETE'
END);
END
数据库触发器
触发器可以定义根据“数据库事件”触发,实际上指的是一个混合的事件行为一个会话(连接)的范围和事件,在单个事务的范围
• CONNECT
• DISCONNECT
• TRANSACTION START
• TRANSACTION COMMIT
• TRANSACTION ROLLBACK
执行数据库触发器和异常处理
CONNECT和DISCONNECT触发器在为此目的创建的事务中执行。如果所有的都顺利执行的话,则提交事务。未捕获的异常导致事务被回滚,且:
• 对于一个CONNECT触发器,然后连接就会断开和异常会返回给客户端
• 对于一个DISCONNECT触发器,不报告异常。连接如预期一样被断开
TRANSACTION触发器在其事务内被执行,开始、提交或回滚时唤起它们。未捕获的异常采取的后续行动取决于事件:
• 在一个TRANSACTION START触发器,异常被报告到客户端且事务被回滚。
• 在一个TRANSACTION COMMIT触发器,异常被报告,到目前为止触发器的操作都将被撤消和取消提交。
• 在一个TRANSACTION COMMITROLLBACK,异常不被报告,事务如预期一样被回滚。
陷阱
很显然这里没有直接的方法知道DISCONNECT或TRANSACTION ROLLBACK是否导致了一个异常。
它也遵循连接到数据库不能发生如果一个CONNECT触发器导致了一个异常,事务不能开始如果 TRANSACTION START 触发器导致了一个异常。两种现象有效地把你关在你的数据库外,直到你在那里禁止数据库触发器和修复糟糕的代码。
触发器禁止
一些Firebrid数据库命令行工具已经提供了开关,管理员可以使用它来禁止数据库触发器的自动触发。到目前为止,它们是:
gbak -nodbtriggers
isql -nodbtriggers
nbackup -T
两个阶段的提交
在两阶段提交的场景, TRANSACTION COMMIT触发器触发在准备阶段,而不是在提交阶段。
一些警告
1.在数据库中相关的事件触发器中使用IN AUTONOMOUS TRANSACTION DO语句关联到事务(TRANSACTION START, TRANSACTION ROLLBACK, TRANSACTION COMMIT)可能会导致自治事务进入一个无限循环。
2. DISCONNECT和TRANSACTION ROLLBACK事件触发器将不被执行,当客户端是通过监控表被断开时(DELETE FROM MON$ATTACHMENTS)。
只有数据库的所有者和管理员有权数据库触发器
使用CREATE TRIGGER创建"数据库触发器"的例子:
1. 为连接到数据库的事件创建一个触发器,记录用户登录到系统日志。触发器以非活跃方式被创建。
CREATE TRIGGER tr_log_connect
INACTIVE ON CONNECT POSITION 0
AS
BEGIN
INSERT INTO LOG_CONNECT (ID,
USERNAME,
ATIME)
VALUES (NEXT VALUE FOR SEQ_LOG_CONNECT,
CURRENT_USER,
CURRENT_TIMESTAMP);
END
2. 为连接到数据库的事件创建一个触发器,在下班时间除了SYSDBA外,不允许其它用登录.
CREATE EXCEPTION E_INCORRECT_WORKTIME 'The working day has not started yet.';
CREATE TRIGGER TR_LIMIT_WORKTIME ACTIVE
ON CONNECT POSITION 1
AS
BEGIN
IF ((CURRENT_USER <> 'SYSDBA') AND
NOT (CURRENT_TIME BETWEEN time '9:00' AND time '17:00')) THEN
EXCEPTION E_INCORRECT_WORKTIME;
END
参阅: ALTER TRIGGER, CREATE OR ALTER TRIGGER, RECREATE TRIGGER, DROP TRIGGER