DML触发器的要点

DML触发器是定义在表上的触发器,由DML事件引发。编写DML触发器的要素是:

* 确定触发的表,即在其上定义触发器的表。

* 确定触发的事件,DML触发器的触发事件有INSERT、UPDATE和DELETE三种,说明见下。

* 确定触发时间。触发的时间有BEFORE和AFTER两种,分别表示触发动作发生在DML语句执行之前和语句执行之后。

* 确定触发级别,有语句级触发器和行级触发器两种。语句级触发器表示SQL语句只触发一次触发器,行级触发器表示SQL语句影响的每一行都要触发一次。

由于在同一个表上可以定义多个DML触发器,因此触发器本身和引发触发器的SQL语句在执行的顺序上有先后的关系。它们的顺序是:

* 如果存在语句级BEFORE触发器,则先执行一次语句级BEFORE触发器。

* 在SQL语句的执行过程中,如果存在行级BEFORE触发器,则SQL语句在对每一行操作之前,都要先执行一次行级BEFORE触发器,然后才对行进行操作。如果存在行级AFTER触发器,则SQL语句在对每一行操作之后,都要再执行一次行级AFTER触发器。

* 如果存在语句级AFTER触发器,则在SQL语句执行完毕后,要最后执行一次语句级AFTER触发器。

DML触发器还有一些具体的问题,说明如下:

* 如果有多个触发器被定义成为相同时间、相同事件触发,且最后定义的触发器是有效的,则最后定义的触发器被触发,其他触发器不执行。

* 一个触发器可由多个不同的DML操作触发。在触发器中,可用INSERTING、DELETING、UPDATING谓词来区别不同的DML操作。这些谓词可以在IF分支条件语句中作为判断条件来使用。

* 在行级触发器中,用:new 和:old(称为伪记录)来访问数据变更前后的值。但要注意,INSERT语句插入一条新记录,所以没有:old记录,而DELETE语句删除掉一条已经存在的记录,所以没有:new记录。UPDATE语句既有:old记录,也有:new记录,分别代表修改前后的记录。引用具体的某一列的值的方法是: :old.字段名或:new.字段名。触发器体内禁止使用COMMIT、ROLLBACK、SAVEPOINT语句,也禁止直接或间接地调用含有上述语句的存储过程。

定义一个触发器时要考虑上述多种情况,并根据具体的需要来决定触发器的种类。

DML触发器的创建

创建DML触发器需要CREATE TRIGGER系统权限。创建DML触发器的语法如下:

CREATE [OR REPLACE] TRIGGER 触发器名

{BEFORE|AFTER|INSTEAD OF} 触发事件1 [OR 触发事件2...]

ON 表名

WHEN 触发条件

[FOR EACH ROW]

DECLARE

声明部分

BEGIN

主体部分

END;

其中:

OR REPLACE:表示如果存在同名触发器,则覆盖原有同名触发器。

BEFORE、AFTER和INSTEAD OF:说明触发器的类型。

WHEN 触发条件:表示当该条件满足时,触发器才能执行。

触发事件:指INSERT、DELETE或UPDATE事件,事件可以并行出现,中间用OR连接。

对于UPDATE事件,还可以用以下形式表示对某些列的修改会引起触发器的动作:

UPDATE OF 列名1,列名2...

ON 表名:表示为哪一个表创建触发器。

FOR EACH ROW:表示触发器为行级触发器,省略则为语句级触发器。

触发器的创建者或具有DROP ANY TIRGGER系统权限的人才能删除触发器。删除触发器的语法如下:

DROP TIRGGER 触发器名

可以通过命令设置触发器的可用状态,使其暂时关闭或重新打开,即当触发器暂时不用时,可以将其置成无效状态,在使用时重新打开。该命令语法如下:

ALTER TRIGGER 触发器名 {DISABLE|ENABLE}

其中,DISABLE表示使触发器失效,ENABLE表示使触发器生效。

同存储过程类似,触发器可以用SHOW ERRORS 检查编译错误。

行级触发器的应用

在行级触发器中,SQL语句影响的每一行都会触发一次触发器,所以行级触发器往往用在对表的每一行的操作进行控制的场合。若在触发器定义中出现FOR EACH ROW子句,则为行级触发器。

【训练1】 创建包含插入、删除、修改多种触发事件的触发器DML_LOG,对EMP表的操作进行记录。用INSERTING、DELETING、UPDATING谓词来区别不同的DML操作。

在创建触发器之前,需要先创建事件记录表LOGS,该表用来对操作进行记录。该表的字段含义解释如下:

LOG_ID:操作记录的编号,数值型,它是该表的主键,由序列自动生成。

LOG_TABLE:进行操作的表名,字符型,非空,该表设计成可以由多个触发器共享使用。比如我们可以为dept表创建类似的触发器,同样将操作记录到该表。

LOG_DML:操作的动作,即INSERT、DELETE或UPDATE三种之一。

LOG_KEY_ID:操作时表的主键值,数值型。之所以记录表的主键,是因为主键是表的记录的惟一标识,可以识别是对哪一条记录进行了操作。对于emp表,主键是empno。

LOG_DATE:操作的日期,日期型,取当前的系统时间。

LOG_USER:操作者,字符型,取当时的操作者账户名。比如登录SCOTT账户进行操作,在该字段中,记录账户名为SCOTT。

步骤1:在SQL*Plus中登录STUDENT账户,创建如下的记录表LOGS:

CREATETABLElogs(

LOG_ID NUMBER(10)PRIMARYKEY,

LOG_TABLE VARCHAR2(10)NOTNULL,

LOG_DML VARCHAR2(10),

LOG_KEY_ID NUMBER(10),

LOG_DATEDATE,

LOG_USER VARCHAR2(15)

);

执行结果:表已创建。

步骤2:创建一个LOGS表的主键序列LOGS_ID_SEQ:

CREATESEQUENCElogs_id_squ INCREMENTBY1

STARTWITH1 MAXVALUE 9999999 NOCYCLE NOCACHE;

执行结果:序列已创建。

步骤3:创建和编译以下触发器:CREATEORREPLACETRIGGERDML_LOG

BEFORE--触发时间为操作前

DELETEORINSERTORUPDATE-- 由三种事件触发

ONemp

FOREACH ROW-- 行级触发器

BEGIN

IF INSERTINGTHEN

INSERTINTOlogsVALUES(logs_id_squ.NEXTVAL,'EMP','INSERT',:new.empno,SYSDATE,USER);

ELSIF DELETINGTHEN

INSERTINTOlogsVALUES(logs_id_squ.NEXTVAL,'EMP','DELETE',:old.empno,SYSDATE,USER);

ELSE

INSERTINTOlogsVALUES(logs_id_squ.NEXTVAL,'EMP','UPDATE',:new.empno,SYSDATE,USER);

ENDIF;

END;

执行结果:

触发器已创建

步骤4:在EMP表中插入记录:

INSERTINTOemp(empno,ename,job,sal)VALUES(8001,'MARY','CLERK',1000);

COMMIT;

执行结果:

已创建1行。

提交完成。

步骤5:检查LOGS表中记录的信息:

SELECT*FROMLOGS;

执行结果为:LOG_ID LOG_TABLE   LOG_DML     LOG_KEY_ID LOG_DATE    LOG_USER

----------------- ----------------- ------------------ ----------------------- ---------------- -------------------

1 EMPINSERT8001     29-3月 -04      STUDENT

已选择 1 行。

说明:本例中在emp表上创建了一个由INSERT或DELETE或UPDATE事件触发的行级触发器,触发器的名称是LOG_EMP。对于不同的操作,记录的内容不同。本例中只插入了一条记录,如果用一条不带WHERE条件的UPDATE语句来修改所有雇员的工资,则将逐行触发触发器。

INSERT、DELETE和UPDATE都能引发触发器动作,在分支语句中使用INSERTING、DELETING和UPDATING来区别是由哪种操作引发的触发器动作。

在本例的插入动作中,LOG_ID字段由序列LOG_ID_SQU自动填充为1;LOGS表LOG_KEY_ID字段记录的是新插入记录的主键8001;LOD_DML字段记录的是插入动作INSERT;LOG_TABLE字段记录当前表名EMP;LOG_DATE字段记录插入的时间04年3月1日;LOG_USER字段记录插入者STUDENT。

【训练3】 创建触发器CHECK_SAL,当对职务为CLERK的雇员的工资修改超出500至2000的范围时,进行限制。

步骤1:创建和编译以下触发器:

Sql代码

CREATEORREPLACETRIGGERCHECK_SAL

BEFORE

UPDATE

ONemp

FOREACH ROW

BEGIN

IF :new.job='CLERK'AND(:new.sal<500OR:new.sal>2000)THEN

RAISE_APPLICATION_ERROR(-20001,'工资修改超出范围,操作取消!');

ENDIF;

END;CREATE OR REPLACE TRIGGER CHECK_SAL

BEFORE

UPDATE

ON emp

FOR EACH ROW

BEGIN

IF :new.job='CLERK' AND (:new.sal<500 OR :new.sal>2000) THEN

RAISE_APPLICATION_ERROR(-20001, '工资修改超出范围,操作取消!');

END IF;

END;

执行结果:

Sql代码

触发器已创建。触发器已创建。

步骤2:在EMP表中插入记录:

Sql代码

UPDATEempSETsal=800WHEREempno=7876;

UPDATEempSETsal=450WHEREempno=7876;

COMMIT;UPDATE emp SET sal=800 WHERE empno=7876;

UPDATE emp SET sal=450 WHERE empno=7876;

COMMIT;

执行结果:

Sql代码

UPDATEempSETsal=450WHEREempno=7876

*

ERROR 位于第 1 行:

ORA-20001: 工资修改超出范围,操作取消!

ORA-06512: 在"STUDENT.CHECK_SAL", line 3

ORA-04088: 触发器'STUDENT.CHECK_SAL'执行过程中出错提交完成。UPDATE emp SET sal=450 WHERE empno=7876

*

ERROR 位于第 1 行:

ORA-20001: 工资修改超出范围,操作取消!

ORA-06512: 在"STUDENT.CHECK_SAL", line 3

ORA-04088: 触发器 'STUDENT.CHECK_SAL' 执行过程中出错提交完成。

步骤3:检查工资的修改结果:

Sql代码

SELECTempno,ename,job,salFROMempWHEREempno=7876;SELECT empno,ename,job,sal FROM emp WHERE empno=7876;

执行结果为:

Sql代码

EMPNO ENAME       JOB               SAL

----------------- ------------- ------------- ------------------------

7876   ADAMS       CLERK             800EMPNO ENAME JOB SAL

------------------ ------------- ------------- ------------------------

7876 ADAMS CLERK 800

说明:在触发器中,当IF语句的条件满足时,即对职务为CLERK的雇员工资的修改超出指定范围时,用RAISE_APPLICATION_ERROR语句来定义一个临时定义的异常,并立即引发异常。由于触发器是BEFORE类型,因此触发器先执行,触发器因异常而终止,SQL语句的执行就会取消。

通过步骤2的执行信息可以看到,第一条语句修改编号为7876的雇员ADAMS的工资为800,成功执行。第二条语句修改雇员ADAMS的工资为450,发生异常,执行失败。这样就阻止了不符合条件的工资的修改。通过步骤3的查询可以看到,雇员ADAMS最后的工资是800,即发生异常之前的修改结果。

语句级触发器的应用

同行级触发器不同,语句级触发器的每个操作语句不管操作的行数是多少,只触发一次触发器,所以语句级触发器适合于对整个表的操作权限等进行控制。在触发器定义中若省略FOR EACH ROW子句,则为语句级触发器。

【训练1】 创建一个语句级触发器CHECK_TIME,限定对表EMP的修改时间为周一至周五的早8点至晚5点。

步骤1:创建和编译以下触发器:

Sql代码

CREATEORREPLACETRIGGERCHECK_TIME

BEFORE

UPDATEORINSERTORDELETE

ONEMP

BEGIN

IF (TO_CHAR(SYSDATE,'DY')IN('SAT','SUN'))

ORTO_CHAR(SYSDATE,'HH24')

ORTO_CHAR(SYSDATE,'HH24')>='17'THEN

RAISE_APPLICATION_ERROR(-20500,'非法时间修改表错误!');

ENDIF;

END;CREATE OR REPLACE TRIGGER CHECK_TIME

BEFORE

UPDATE OR INSERT OR DELETE

ON EMP

BEGIN

IF (TO_CHAR(SYSDATE,'DY') IN ('SAT','SUN'))

OR TO_CHAR(SYSDATE,'HH24')< '08'

OR TO_CHAR(SYSDATE,'HH24')>='17' THEN

RAISE_APPLICATION_ERROR(-20500,'非法时间修改表错误!');

END IF;

END;

执行结果:

Sql代码

触发器已创建。触发器已创建。

步骤2:当前时间为18点50分,在EMP表中插入记录:

Sql代码

UPDATEEMPSETSAL=3000WHEREEMPNO=7369;UPDATE EMP SET SAL=3000 WHERE EMPNO=7369;

显示结果为:

Sql代码

UPDATEEMPSETSAL=3000WHEREEMPNO=7369

*

ERROR 位于第 1 行:

ORA-20500: 非法时间修改表错误!

ORA-06512: 在"STUDENT.CHECK_TIME", line 5

ORA-04088: 触发器'STUDENT.CHECK_TIME'执行过程中出错UPDATE EMP SET SAL=3000 WHERE EMPNO=7369

*

ERROR 位于第 1 行:

ORA-20500: 非法时间修改表错误!

ORA-06512: 在"STUDENT.CHECK_TIME", line 5

ORA-04088: 触发器 'STUDENT.CHECK_TIME' 执行过程中出错

说明:通过引发异常限制对数据库进行的插入、删除和修改操作的时间。SYSDATE用来获取系统当前时间,并按不同的格式字符串进行转换。“DY”表示获取英文表示的星期简写,“HH24”表示获取24小时制时间的小时。

当在18点50分修改表中的数据时,由于时间在8点至17点(晚5点)之外,所以产生“非法时间修改表错误”的用户自定义错误,修改操作终止。

oracle dml触发器 获取当前执行sql语句,Oracle DML触发器相关推荐

  1. oracle中执行动态sql语句吗,oracle中有没有可动态执行sql语句的函数

    oracle中有没有可动态执行sql语句的函数 关注:233  答案:2  手机版 解决时间 2021-03-05 15:53 提问者祗剩寂寞 2021-03-04 22:38 oracle中有没有可 ...

  2. PHP获取MySQL执行sql语句的查询时间

    PHP获取MySQL执行sql语句的查询时间 1. $t1=microtime(true); mysql_query($sql); echo microtime(true)-$t1; 2. //计时开 ...

  3. oracle删除一张表的sql语句,oracle删除表的语句

    oracle删除一个用户下的表的sql语句是什么啊 删除用户所有表declarecursor c1 is select table_name from dba_tables where owner=' ...

  4. php查看mysql最近执行过的sql_PHP获取MySQL执行sql语句的查询时间

    //计时开始 runtime(); //执行查询 mysql_query($sql); //计时结束. echo runtime(1); //计时函数 function runtime($mode=0 ...

  5. oracle 数据库如何获取一条sql语句执行所消耗耗费的时间?

    SQL> set timing on; SQL> select count(*) from test; COUNT(*) ---------- 22590 已用时间: 00: 00: 00 ...

  6. mysql执行sql语句按钮_mysql执行sql语句过程

    开发人员基本都知道,我们的数据存在数据库中(目前最多的是mysql和oracle,由于作者更擅长mysql,所以这里默认数据库为mysql),服务器通过sql语句将查询数据的请求传入到mysql数据库 ...

  7. Oracle调用接口(OCI)源码剖析(2):执行SQL语句并获取结果

    概述 接着上一篇文章<Oracle调用接口(OCI)源码剖析(1):创建数据库连接>,我们继续对OCI中执行SQL语句并获取结果的源码进行剖析.该操作主要是由两个函数完成的:CDbExec ...

  8. Python 技术篇-连接oracle数据库并执行sql语句实例演示,python连接oracle数据库oci详细配置方法

    Python 连接 Oracle 数据库 第一章:连接 oracle 数据与环境配置 ① 连接 oracle 数据库效果演示 ② oci 下载 ③ oci 配置 ④ 环境变量配置 ⑤ 检测是否有 or ...

  9. 在Oracle中不通过存储过程一次执行多条SQL语句Oracle PL/SQL

    PL/SQL是ORACLE对标准数据库语言的扩展,ORACLE公司已经将PL/SQL整合到ORACLE 服务器和其他工具中了,近几年中更多的开发人员和DBA开始使用PL/SQL,本文将讲述PL/SQL ...

最新文章

  1. 影像锐化工具_如何以及为什么要进行工具改造:花在锐化斧头上的时间永远不会浪费...
  2. 结账任务 - 年终结账
  3. [UE4]自动旋转组件
  4. 智能灯控制页面用HTML编写,智能家居系统中智能化灯光控制的设计实现
  5. SpringCloudSpringBootmybatis分布式微服务云架构-hystrix参数详解
  6. 差别对待!双一流高校只给2020级博士涨“工资”,不顾其他年级引争议
  7. 直播程序源码更简单的搭建方法
  8. 生命游戏(Anylogic实现)
  9. mysql 将中文转换成拼音_mysql 如何将中文转拼音
  10. 陌生人交友软件有哪些?陌生人社交APP排名|良心推荐
  11. Iphone开发(九)理解subView,手动实现多个视图切换
  12. android定时启动 tasker,Android 神器 Tasker 个人的一些配置
  13. linux网络延迟命令,2. Linux使用ping命令查看网络延迟
  14. Arduino 学习思考与记录
  15. java转码及页面乱码原因分析
  16. matlab将图片旋转的代码_我的MATLAB魔方新玩法:拼出任意图案!
  17. 小米手机5X获得Root权限的方法
  18. 鼠标右键转圈圈_电脑一右键就一直转圈怎么办_win10鼠标一点右键就转圈圈的解决方法...
  19. Python特殊运算符号(幂运算,除法运算)
  20. 程序员用学位证吗_如何成为没有学位的程序员?

热门文章

  1. 第一次使用IDEA提交项目到码云
  2. 机器学习——数据仓库与数据挖掘——期末复习(简答题)
  3. 计算机图形学画圆公式推导,计算机图形学画圆方法(范文).doc
  4. 企业型业务事务一体化平台功能侧重点(服装行业)
  5. jquery ajax post 415,415不支持的媒体类型jQuery Ajax
  6. DEV-C++下载方法
  7. 习题 猜数字游戏提示
  8. 计算机二级Python 操作题知识点及例题总结
  9. 华为机试——简单题整合(二)(C++)
  10. python新闻评论分析_今日头条新闻评论获取