Oracle笔记:触发器

触发器是一种特殊类型的存储过程,类似于其他编程语言的事件函数,当有操作影响到触发器管理的数据时。触发器就会自动发生。触发器也是保护数据完整性的一种重要方法,于存储过程不同的是,触发器是通过事件进行触发被执行,存储过程需要被调用执行。oracle提供5种类型的触发器:语句触发器,行触发器,INSTEAD OF触发器,系统条件触发器和用户事件触发器。BEFORE:语句执行前触发;AFTER:语句执行后触发

01 语句触发器

语句触发器是在表上或则某些情况下的视图上执行的特定语句或则语句组上的触发器,于INSERT,UPDATE,DELETE或则组合上进行关联。但是无论使用什么样的组合,各个语句触发器都只会针对指定语句激活一次。

创建语句触发器:

create or replace trigger tri_1
before insert or delete or update on stu
begin
	if inserting then
		dbms_output.put_line('emp数据表有数据inserting...');
	end if;
	if deleting then
		dbms_output.put_line('emp数据表有数据deleting...');
	end if;
	if updating then
		dbms_output.put_line('emp数据表有数据updating...');
	end if;
end;

测试如图:
Oracle笔记:触发器_第1张图片
Oracle笔记:触发器_第2张图片
Oracle笔记:触发器_第3张图片

02 行触发器

行触发器是指为受影响的各个行激活触发器,即每影响到一行记录就触发一次。行触发器的定义语句与语句触发器类似,只需要加上for each row参数。

创建行触发器:

drop trigger tri_2;
create or replace trigger tri_2
after insert or delete or update on stu
for each row
begin
	if inserting then
		dbms_output.put_line('inserting...');
	end if;
	if deleting then
		dbms_output.put_line('deleting...');
	end if;
	if updating then
		dbms_output.put_line('updating...');
	end if;
end;

测试如图:
注意:对于表同时创建行触发器和语句触发器时会被同样触发,先触发语句触发器时再触发行触发器。
Oracle笔记:触发器_第4张图片

03 指定列触发器

使用updete of columnname on tablename创建指定列触发器:

create or replace trigger tri_3
after update of no on stu
for each row
begin
	if updating then
		raise_application_error(-20001,'不能修改emp.no列的数据');
	end if;
end;

测试如图:
Oracle笔记:触发器_第5张图片

04 INSTEAD OF触发器

INSTEAD OF触发器是针对视图对象的触发器;用于对视图插入数据时实现对基于视图基本表的数据插入。

创建INSTEAD OF触发器:

create or replace trigger tri_4
instead of insert on grade_v
for each row
begin
	insert into STU(NO,NAME,GENTLE,AGE,DEPT)
	values(:new.NO,:new.NAME,:new.GENTLE,:new.AGE,:new.DEPT);
	insert into GRADE(NO,NAME,SCORE)
	values(:new.NO,:new.GRADENAME,:new.SCORE);
end;

测试如图:
Oracle笔记:触发器_第6张图片
在这里插入图片描述
Oracle笔记:触发器_第7张图片
Oracle笔记:触发器_第8张图片
使用INSTEAD OF注意事项:
1.只能被创建在视图上,并却该视图没有指定WITH CHECK OPTION选项。
2.不呢个指定BEFORE或AFTER。
3.FOR EACH ROW子句是可选的,即INSTEAD OF触发器只能在行级上触发,或只能是行级触发器,没必要指定。

05 用户事件触发器

用户事件触发器是在用户事件上触发的,一般包括:用户登录,注销,修改结构等,可以在CREATE,ALTER,DROP等DLL操作或数据库系统上被触发。

用户事件触发器事件说明如图:
Oracle笔记:触发器_第9张图片
创建用户事件触发器:

create or replace trigger tri_5
after ddl on schema
begin
	dbms_output.put_line('执行了ddl语句');
end;

测试如图:
Oracle笔记:触发器_第10张图片

06 系统事件触发器

系统事件触发器是在系统事件上触发的触发器,系统事件一般包括数据库启动,关闭,用户的登录与退出,服务器错误等事件,其可以在对数据库的STARTUP,SHUTDOWN及用户的LOGON,LOGOFF等操作时被触发
Oracle笔记:触发器_第11张图片
Oracle笔记:触发器_第12张图片
创建系统事件触发器:

create table logon_event(
user_name varchar2(20),
address varchar2(20),
logon_date timestamp,
logoff_date timestamp
);

create or replace trigger tri_6
after logon on database
begin
    insert into logon_event(user_name,address,logon_date)
    values(ora_login_user,ora_client_ip_address,systimestamp);
end;

在这里插入图片描述

07 使用触发器记录日志

创建记录日志触发器及相关对象

--创建日志表
CREATE TABLE stu_log(
LOGID NUMBER,
LOGACTION VARCHAR2(1),
NO      VARCHAR2(20),
NAME    VARCHAR2(20),
GENTLE  VARCHAR2(4),
AGE     NUMBER(2),
DEPT    VARCHAR2(20),
LOGTIME DATE
);

--创建序列号
DROP SEQUENCE stu_seq;
CREATE SEQUENCE stu_seq
    START WITH 1
    MAXVALUE 999999999999999999999999999
    MINVALUE 1
    NOCYCLE
    NOCACHE
    NOORDER;


--创建记录日志触发器
CREATE OR REPLACE TRIGGER tri_7
AFTER INSERT OR DELETE OR UPDATE ON stu
REFERENCING NEW AS NEW OLD AS OLD--BEGIN...END中使用别名来引用
FOR EACH ROW--FOR EACH ROW表示是行级触发器,每操作成功一行就会触发一次
DECLARE
   currseq   stu_log.LOGID%TYPE;
BEGIN
    SELECT stu_seq.CURRVAL INTO currseq FROM DUAL;
	IF INSERTING THEN
      INSERT INTO stu_log(LOGID,
                          LOGACTION,
                          NO,
                          NAME,
                          GENTLE,
                          AGE,
                          DEPT,
                          LOGTIME)
      VALUES (currseq,
              'I',
              :NEW.NO,
              :NEW.NAME,
              :NEW.GENTLE,
              :NEW.AGE,
              :NEW.DEPT,
              (SELECT SYSDATE FROM DUAL));
	END IF;
	IF DELETING THEN
      DELETE FROM stu_log WHERE LOGID = currseq AND LOGACTION IN ('O', 'U');
        
      INSERT INTO stu_log(LOGID,
                          LOGACTION,
                          NO,
                          NAME,
                          GENTLE,
                          AGE,
                          DEPT,
                          LOGTIME)
      VALUES (currseq,
              'D',
              :OLD.NO,
              :OLD.NAME,
              :OLD.GENTLE,
              :OLD.AGE,
              :OLD.DEPT,
              (SELECT SYSDATE FROM DUAL));
	END IF;
	IF UPDATING THEN
      INSERT INTO stu_log(LOGID,
                          LOGACTION,
                          NO,
                          NAME,
                          GENTLE,
                          AGE,
                          DEPT,
                          LOGTIME)
      VALUES (currseq,
              'U',
              :NEW.NO,
              :NEW.NAME,
              :NEW.GENTLE,
              :NEW.AGE,
              :NEW.DEPT,
              (SELECT SYSDATE FROM DUAL));
      INSERT INTO stu_log(LOGID,
                          LOGACTION,
                          NO,
                          NAME,
                          GENTLE,
                          AGE,
                          DEPT,
                          LOGTIME)
      VALUES (currseq,
              'O',
              :OLD.NO,
              :OLD.NAME,
              :OLD.GENTLE,
              :OLD.AGE,
              :OLD.DEPT,
              (SELECT SYSDATE FROM DUAL));
	END IF;
END;

测试如图
Oracle笔记:触发器_第13张图片
在这里插入图片描述

Oracle笔记:触发器_第14张图片
在这里插入图片描述
Oracle笔记:触发器_第15张图片
在这里插入图片描述

OTHERS

--查看触发器
select * from user_triggers where table_name = 'STU';--要大写!!!
--禁用/启动触发器
alter trigger tri_1 disable;
alter trigger tri_1 enable;
--以表为单位禁用/启动触发器
alter table stu disable all triggers;
alter table stu enable all triggers;
--删除触发器
--drop trigger tri_1;

修改触发器关联表时需要先drop trigger;否则会遇到如下情况:
Oracle笔记:触发器_第16张图片
Oracle笔记:触发器_第17张图片

DROP TABLE STU CASCADE CONSTRAINTS;
CREATE TABLE STU
(
  NO      VARCHAR2(20 BYTE),
  NAME    VARCHAR2(20 BYTE),
  GENTLE  VARCHAR2(4 BYTE),
  AGE     NUMBER(2),
  DEPT    VARCHAR2(20 BYTE)
);

SET DEFINE OFF;
Insert into STU
   (NO, NAME, GENTLE, AGE, DEPT)
 Values
   ('120006', '李飒', '男', 12, '12工商管理');
Insert into STU
   (NO, NAME, GENTLE, AGE, DEPT)
 Values
   ('120005', '林琳', '女', 22, '12计算机');
Insert into STU
   (NO, NAME, GENTLE, AGE, DEPT)
 Values
   ('120004', '杨过', '男', 22, '12计算机');
Insert into STU
   (NO, NAME, GENTLE, AGE, DEPT)
 Values
   ('120003', '张清', '女', 21, '12外语');
Insert into STU
   (NO, NAME, GENTLE, AGE, DEPT)
 Values
   ('120001', '陈诚', '男', 23, '12计算机');
Insert into STU
   (NO, NAME, GENTLE, AGE, DEPT)
 Values
   ('120002', '李宗赫', '男', 25, '12图形');
Insert into STU
   (NO, NAME, GENTLE, AGE, DEPT)
 Values
   ('120007', '李飒11', '男', 12, '12工商管理');
COMMIT;

------------------------
DROP TABLE GRADE CASCADE CONSTRAINTS;
CREATE TABLE GRADE
(
  NO     VARCHAR2(10 BYTE)                      NOT NULL,
  NAME   VARCHAR2(20 BYTE),
  SCORE  NUMBER
);
SET DEFINE OFF;
Insert into GRADE
   (NO, NAME, SCORE)
 Values
   ('120001', '计算机基础', 85);
Insert into GRADE
   (NO, NAME, SCORE)
 Values
   ('120003', '计算机基础', 96);
Insert into GRADE
   (NO, NAME, SCORE)
 Values
   ('120004', '计算机基础', 60);
COMMIT;

---------------------
DROP VIEW GRADE_V;
CREATE OR REPLACE FORCE VIEW GRADE_V
(
    NO,
    NAME,
    GENTLE,
    AGE,
    DEPT,
    GRADENAME,
    SCORE
)
AS
    SELECT STU.NO          AS NO,
           STU.NAME        AS NAME,
           STU.GENTLE      AS GENTLE,
           STU.AGE         AS AGE,
           STU.DEPT        AS DEPT,
           GRADE.NAME      AS GRADENAME,
           GRADE.SCORE     AS SCORE
      FROM STU, GRADE
     WHERE STU.NO = GRADE.NO;

你可能感兴趣的:(Oracle)