失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > oracle dml触发器 获取当前执行sql语句 Oracle DML触发器

oracle dml触发器 获取当前执行sql语句 Oracle DML触发器

时间:2022-03-07 22:54:39

相关推荐

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触发器》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。