oracle dml触发器 获取当前执行sql语句,Oracle DML触发器
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触发器相关推荐
- oracle中执行动态sql语句吗,oracle中有没有可动态执行sql语句的函数
oracle中有没有可动态执行sql语句的函数 关注:233 答案:2 手机版 解决时间 2021-03-05 15:53 提问者祗剩寂寞 2021-03-04 22:38 oracle中有没有可 ...
- PHP获取MySQL执行sql语句的查询时间
PHP获取MySQL执行sql语句的查询时间 1. $t1=microtime(true); mysql_query($sql); echo microtime(true)-$t1; 2. //计时开 ...
- oracle删除一张表的sql语句,oracle删除表的语句
oracle删除一个用户下的表的sql语句是什么啊 删除用户所有表declarecursor c1 is select table_name from dba_tables where owner=' ...
- php查看mysql最近执行过的sql_PHP获取MySQL执行sql语句的查询时间
//计时开始 runtime(); //执行查询 mysql_query($sql); //计时结束. echo runtime(1); //计时函数 function runtime($mode=0 ...
- oracle 数据库如何获取一条sql语句执行所消耗耗费的时间?
SQL> set timing on; SQL> select count(*) from test; COUNT(*) ---------- 22590 已用时间: 00: 00: 00 ...
- mysql执行sql语句按钮_mysql执行sql语句过程
开发人员基本都知道,我们的数据存在数据库中(目前最多的是mysql和oracle,由于作者更擅长mysql,所以这里默认数据库为mysql),服务器通过sql语句将查询数据的请求传入到mysql数据库 ...
- Oracle调用接口(OCI)源码剖析(2):执行SQL语句并获取结果
概述 接着上一篇文章<Oracle调用接口(OCI)源码剖析(1):创建数据库连接>,我们继续对OCI中执行SQL语句并获取结果的源码进行剖析.该操作主要是由两个函数完成的:CDbExec ...
- Python 技术篇-连接oracle数据库并执行sql语句实例演示,python连接oracle数据库oci详细配置方法
Python 连接 Oracle 数据库 第一章:连接 oracle 数据与环境配置 ① 连接 oracle 数据库效果演示 ② oci 下载 ③ oci 配置 ④ 环境变量配置 ⑤ 检测是否有 or ...
- 在Oracle中不通过存储过程一次执行多条SQL语句Oracle PL/SQL
PL/SQL是ORACLE对标准数据库语言的扩展,ORACLE公司已经将PL/SQL整合到ORACLE 服务器和其他工具中了,近几年中更多的开发人员和DBA开始使用PL/SQL,本文将讲述PL/SQL ...
最新文章
- 影像锐化工具_如何以及为什么要进行工具改造:花在锐化斧头上的时间永远不会浪费...
- 结账任务 - 年终结账
- [UE4]自动旋转组件
- 智能灯控制页面用HTML编写,智能家居系统中智能化灯光控制的设计实现
- SpringCloudSpringBootmybatis分布式微服务云架构-hystrix参数详解
- 差别对待!双一流高校只给2020级博士涨“工资”,不顾其他年级引争议
- 直播程序源码更简单的搭建方法
- 生命游戏(Anylogic实现)
- mysql 将中文转换成拼音_mysql 如何将中文转拼音
- 陌生人交友软件有哪些?陌生人社交APP排名|良心推荐
- Iphone开发(九)理解subView,手动实现多个视图切换
- android定时启动 tasker,Android 神器 Tasker 个人的一些配置
- linux网络延迟命令,2. Linux使用ping命令查看网络延迟
- Arduino 学习思考与记录
- java转码及页面乱码原因分析
- matlab将图片旋转的代码_我的MATLAB魔方新玩法:拼出任意图案!
- 小米手机5X获得Root权限的方法
- 鼠标右键转圈圈_电脑一右键就一直转圈怎么办_win10鼠标一点右键就转圈圈的解决方法...
- Python特殊运算符号(幂运算,除法运算)
- 程序员用学位证吗_如何成为没有学位的程序员?