`

精通Oracle10编程SQL(13)开发触发器

阅读更多
/*
 *开发触发器
 */
--得到日期是周几
select to_char(sysdate+4,'DY','nls_date_language=AMERICAN') from dual;

select to_char(sysdate,'DY','nls_date_language=AMERICAN') from dual;

--建立BEFORE语句触发器
CREATE OR REPLACE TRIGGER tr_sec_emp
before insert or update or delete on emp
begin
  if to_char(sysdate,'DY','nls_date_language=AMERICAN')
     IN('SAT','SUN') THEN
     raise_application_error(-20001,'不能在休息日改变雇员信息');
  end if;
end;

--在建立了触发器tr_sec_emp之后,如果是星期六、星期日在EMP表上执行DML操作,则会显示错误信息
update emp set sal=sal*1.1 where deptno=1;

--使用条件谓词
CREATE OR REPLACE TRIGGER tr_sec_emp
before insert or update or delete on emp
begin
  if to_char(sysdate,'DY','nls_date_language=AMERICAN')
     in('SAT','SUN') then
     case 
       when inserting then
          raise_application_error(-20001,'不能在休息日增加雇员');
       when updating then
          raise_application_error(-20002,'不能在休息日更新雇员');
       when deleting then
          raise_application_error(-20003,'不能在休息日解雇雇员');
     end case;
  end if;
end;

--建立AFTER语句触发器
--为了审计DML操作,或者在DML操作之后执行汇总运算,可以使用AFTER语句触发器
--例如,为了审计在EMP表上INSERT,UPDATE和DELETE的操作次数,可以建立AFTER触发器
--在建立AFTER触发器之前,首先建立审计表audit_table
CREATE TABLE audit_table(
  name VARCHAR2(20),ins int,upd int,del int,starttime date,endtime date);
  
--为了审计在EMP表上DML操作执行的次数、最早执行时间和最近执行时间,需要建立AFTER语句触发器
CREATE OR REPLACE TRIGGER tr_aduit_emp
after insert or update or delete on emp
declare
   v_temp int;
begin
   select count(*) into v_temp from audit_table where name='EMP';
   if v_temp = 0 then
      insert into audit_table values('EMP',0,0,0,SYSDATE,null);
   end if;
   case
      when inserting then
          update audit_table set ins=ins+1,endtime=sysdate where name='EMP';
      when updating then
          update audit_table set upd=upd+1,endtime=sysdate where name='EMP';
      when deleting then
          update audit_table set del=del+1,endtime=sysdate where name='EMP';
   end case;
end;

--在建立了触发器tr_audit_emp之后,在EMP表上执行DML操作时,都会将DML操作次数以及时间段记录在审计表audit_table中
update emp set sal=2000 where empnoo=7788;
update emp set sal=2000 where empnoo=1111;
select * from audit_table;

select * from emp;

--行触发器
--行触发器是指执行DML操作时,每作用一行就触发一次的触发器
--建立BEFORE行触发器
--下面确保雇员工资不能低于其原有工资为例,说明建立BEFORE行触发器的方法
CREATE OR REPLACE TRIGGER tr_emp_sal
BEFORE update of sal on emp
for each row
begin
   if :new.sal<:old.sal then
      raise_application_error(-20010,'工资只涨不降');
   end if;
end;

--在建立触发器tr_emp_sal之后,如果雇员新工资低于其原有工资,则会提示错误信息。
update emp set sal=80 where empno=7788;

select * from emp;

--建立AFTER行触发器
--下面以审计雇员工资变化为例,说明使用AFTER行触发器的方法
--在建立触发器之前,首先应建立存放审计数据的表audit_emp_change
CREATE TABLE audit_emp_change(
   name varchar2(10),oldsal number(6,2),
   newsal number(6,2),time date);

--为了审计所有雇员的工资变化和雇员工资的更新日期,必须要建立AFTER行触发器
CREATE OR REPLACE TRIGGER tr_sal_change
after update of sal on emp
for each row 
declare
   v_temp int;
begin
   select count(*) into v_temp from audit_emp_change where name=:old.ename;
   if v_temp=0 then
      insert into audit_emp_change values(:old.ename,:old.sal,:new.sal,sysdate);
   else
      update audit_emp_change set oldsal=:old.sal,newsal=:new.sal,time=sysdate where name=:old.ename;
   end if;
end;

--在建立触发器tr_sal_change之后,当修改雇员工资时,会将每个雇员的工资变化全部写入到审计表audit_empO_change中
update emp set sal=sal*1.1 where deptno=1;

select * from audit_emp_change;

select * from emp;

--限制行触发器
--当使用行触发器时,默认情况下会在每个被作用行上执行一次触发器代码
--为了使得在特定条件下执行行触发器代码,就需要使用WHERE子句对触发条件加以限制
--下面以审计岗位为"manager"的雇员工资变化为例,说明限制行触发器的方法
CREATE OR REPLACE TRIGGER tr_sal_change
AFTER UPDATE OF sal ON emp
for each row
when (upper(old.job)=upper('manager'))
declare
   v_temp int;
begin
   select count(*) into v_temp from audit_emp_change
      where name=:old.ename;
   if v_temp=0 then
      insert into audit_emp_change values(:old.ename,:old.sal,:new.sal,sysdate);
   else
      update audit_emp_change set oldsal=:old.sal,newsal=:new.sal,time=sysdate where name=:old.ename;
   end if;
end;

--当建立触发器tr_sal_change时,因为使用WHERE子句指定了触发条件,所以只有在满足触发条件时才会执行触发器代码
update emp set sal=sal*1.1 where deptno=2;


--DML触发器使用注意事项
--当编写DML触发器时,触发器代码不能从触发器所对应的基表中读取数据。
--例如,如果要基于EMP表建立触发器,那么该触发器的执行代码不能包含对EMP表的查询操作
--尽管在建立触发器时不会出现任何错误,但在执行相应触发操作时会显示错误信息。
--假定希望雇员工资不能超过当前的最高工资,并使用触发器实现该规则
CREATE OR REPLACE TRIGGER tr_emp_sal
before update of sal on emp
for each row
declare
   maxsal number(6,2);
begin
   select max(sal) into maxsal from emp;
   if :new.sal>maxsal then
      raise_application_error(-20010,'超出工资上限');
   end if;
end;

--如上所示,当建立触发器tr_emp_sal时,不会显示任何错误。但因为触发器代码引用了基表emp,所以在执行UPDATE操作时会出错
update emp set sal=6000 where empno=7788;


--使用DML触发器
--为了确保数据库数据满足特定的商业规则或企业逻辑,可以使用约束、触发器和子程序实现。因为约束性能最好,实现最简单,所以首选约束
--如果使用约束不能实现特定规则,那么应该选择触发器
--如果触发器仍然不能实现特定规则,那么应该选择子程序(过程和函数)
--DML触发器可以用于实现数据安全保护、数据审计、数据完整性、参照完整性、数据复制等功能

--控制数据安全
--在服务器级控制数据安全是通过授予和收回对象权限来完成的,如
grant select,insert,update,delete on emp to smith;

--为了实现更复杂的安全模型(例如限制要修改的数据、修改时间等),就需要使用DML触发器了
--下面以限制用户在正常工作时间(9:00-17:00)改变EMP表数据为例,说明使用DML触发器控制数据安全的方法
create or replace trigger tr_emp_time
before insert or update or delete on emp
begin
   if to_char(sysdate,'HH24') not between '9' and '17' then
      raise_application_error(-20101,'非工作时间');
   end if;
end;

--建立了触发器tr_emp_time之后,只能在9:00-17:00之间在EMP表上执行DML操作,如果不在该时间段,则会显示错误信息
update emp set sal=3200 where empno=7788;

--实现数据审计
--审计可以用于监视非法和可疑的数据库活动,ORACLE数据库本身提供了审计功能
--例如,如果要对EMP表上的DML操作进行审计,可以执行如下命令
AUDIT INSERT,UPDATE,DELETE ON emp;
--如上所示,在设置了审计选项之后,如果在EMP表上执行INSERT、UPDATE和DELETE操作,ORACLE会将关于SQL操作的信息(用户、时间等)写入到数据字典中。
--注意,使用数据库审计只能审计SQL操作,而不会记载数据变化。
--为了审计SQL操作所引起的数据变化,必段要使用DML触发器
CREATE OR REPLACE TRIGGER tr_sal_change
after update of sal on emp
for each row
declare
   v_temp int;
begin
   select count(*) into v_temp from audit_emp_change
       where name=:old.ename;
   if v_temp=0 then
      insert into audit_emp_change values(:old.ename,:old.sal,:new.sal,sysdate);
   else
      update audit_emp_change set oldsal=:old.sal,newsal=:new.sal,time=sysdate where name=:old.ename;
   end if;
end;

--在建立了触发器tr_sal_change之后,当修改雇员工资时,会将每个雇员的工资变化全部写入到审计表audit_emp_change中
update emp set sal=sal*1.1 where deptno=1;

select * from audit_emp_change;

select * from emp;


--实现数据完整性
--数据完整性用于确保数据库数据满足特定的商业逻辑或企业规则,数据完整性可以使用约束、触发器和子程序实现。因为约束的实现最简单,性能也最好
--所以实现数据完整性首选约束。
--例如,为了限制雇员工资不能低于800元,可以选用CHECK约束。示例如下:
alter table emp add constraint ck_sal check(sal>=800);

--但某些情况下使用约束无法实现特定的商业规则,此时可以使用触发器来实现数据完整性。
--例如,假定希望雇员的新工资不能低于其原工资,但也不能高出原工资的20%,使用约束显然无法实现该规则,但通过触发器却可以实现该项规则
CREATE OR REPLACE TRIGGER tr_check_sal
before update of sal on emp
for each row
when (new.sal<old.sal or new.sal>1.2*old.sal)
begin
   raise_application_error(-20931,'工资只升不降,并且升幅不能超过20%');
end;

--在建立了触发器tr_check_sal之后,如果雇员新工资不符合相应规则,则会提示错误信息
update emp set sal=sal*1.25 where empno=7788;

--实现参照完整性
--参照完整性是指若两个表之间具有主从关系(也即主外键关系),当删除主表数据时,必须确保相关的从表数据已经被删除
--当修改主表的主键列数据时,必须确保相关的从表数据已经被修改。
--为了实现级联删除,可以在定义外部键约束时指定ON DELETE CASCADE关键字
--示例如下:
ALTER TABLE emp add constraint fk_deptno
  foreign key(deptno) references dept(deptno)
  on delete cascade;
  
--当用如上方式建立了外部键约束fk_deptno之后,在删除主表DEPT的数据时,会同时删除从表EMP的所有相关数据。
--但使用约束却不能实现级联更新,如果要更新DEPT表的部门号,则会显示错误信息

update dept set deptno=5 where deptno=1;

--原因是EMP表包含有该部门的相应雇员。为了实现级联更新,可以使用触发器,示例如下:
CREATE OR REPLACE TRIGGER tr_update_cascade
after update of deptno on dept
for each row
begin
  update emp set deptno=:new.deptno where deptno=:old.deptno;
end;

--在建立了触发器tr_update_cascade之后,当更新DEPT表的部门号时,会级联更新EMP表的相应雇员的部门号
update dept set deptno=5 where deptno=1;

select ename from emp where deptno=5;

select * from dept;
select * from emp;

delete dept where deptno >=7;


--建立INSTEAD OF触发器
--对于简单视图,可以直接执行 INSERT、UPDATE和DELETE操作
--但是对于复杂视图,不允许直接执行INSERT、UPDATE和DELETE操作。
--当视图符合以下任何一种情况时,都不允许直接执行DML操作
--1.具有集合操作符(UNION,UNION ALL,INTERSECT,MINUS)
--2.具有分组函数(MIN,MAX,SUM,AVG,COUNT等)
--3.具有GROUP BY,CONNECT BY或START WITH等子句
--4.具有DISTINCT关建字
--5.具有连接查询
--为了在具有以上情况的复杂视图上执行DML操作,必须要基于视图建立INSTEAD-OF触发器
--在建立了INSTEAD-OF触发器之后,就可以基于复杂视图执行INSERT,UPDATE和DELETE语句。但建立INSTEAD-OF触发器有以下注意事项
--1.INSTEAD OF选项只适用于视图
--2.当基于视图建立触发器时,不能指定BEFORE和AFTER选项
--3.在建立视图时没有指定WITH CHECK OPTION选项
--4.当建立INSTEAD OF触发器时,必须指定FOR EACH ROW选项

--建立复杂视图dept_emp
--视图是逻辑表,本身没有任何数据。视图只是对应于一条SELECT语句,当查询视图时,其数据实际是从视图基表上取得。
--为了简化部门及其雇员信息的查询,应建立复杂视图dept_emp
CREATE OR REPLACE VIEW dept_emp as 
select a.deptno,a.dname,b.empno,b.ename
from dept a,emp b
where a.deptno=b.deptno;

--当执行以上语句建立了复杂视图dept_emp之后,直接查询视图dept_emp会显示部门及其雇员信息,但不允许执行DML操作
select * from dept_emp where deptno=1;

--建立INSTEAD-OF触发器
CREATE OR REPLACE TRIGGER tr_instead_of_dept_emp
instead of insert on dept_emp
for each row
declare
   v_temp int;
begin
   select count(*) into v_temp from dept
      where deptno=:new.deptno;
   if v_temp=0 then
      insert into dept(deptno,dname) values(:new.deptno,:new.dname);
   end if;
   select count(*) into v_temp from emp
      where empno=:new.empno;
   if v_temp=0 then
      insert into emp(empno,ename,deptno) values(:new.empno,:new.ename,:new.deptno);
   end if;
end;

--当建立了INSTEAD-OF触发器tr_instead_of_dept_emp之后,就可以在复杂视图dept_emp上执行INSERT操作了
insert into dept_emp values(50,'ADMIN','1223','MARY');
insert into dept_emp values(10,'ADMIN','1224','BAKE');

select * from dept_emp;

select * from dept;

select * from emp;


--建立系统事件触发器
--建立例程启动和关闭触发器
create table event_table(event varchar2(30),time date);
--例程启动触发器和例程关闭触发器只有特权用户才能建立,并且例程启动触发器只能使用AFTER关键字,而例程关闭触发器只能使用BEFORE关键字
CREATE OR REPLACE TRIGGER tr_startup
after startup on database
begin
   insert into event_table values(ora_sysevent,sysdate);
end;

create or replace trigger tr_shutdown
before shutdown on database
begin
   insert into event_table values(ora_sysevent,sysdate);
end;

--在建立了触发器tr_startup之后,当打开数据库之后,会执行该触发器的相应代码
--在建立了触发器tr_shutdown之后,在关闭例之前,会执行该触发器的相应代码,但SHUTDOWN ABORT命令不会触发该触发器
shutdown

startup

select event,to_char(time,'YYYY/MM/DD HH24:MI') time from event_table;


--建立登录和退出触发器
--首先建立专门存放登录和退出的信息表LOG_TABLE
create table log_table(username varchar2(20),logon_time date,logoff_time date,address varchar2(20));

--注意,登录触发器和退出触发器一定要以特权用户身份建立,并且登录触发器只能使用AFTER关键字,而退出触发器只能使用BEFORE关键字
create or replace trigger tr_logon
after logon on database
begin
  insert into log_table(username,logon_time,address) values(ora_login_user,sysdate,ora_client_ip_address);
end;

create or replace trigger tr_logoff
before logoff on database
begin
   insert into log_table(username,logoff_time,address) values(ora_login_user,sysdate,ora_client_ip_address);
end;

--在建立了触发器tr_logon之后,当用户登录到数据库之后,会执行其触发器代码
--在建立了触发器tr_logoff之后,当用户断开数据库连接之前,会执行其触发器代码
select * from log_table;

--建立DDL触发器
--为了记载所发生的DDL事件(CREATE,ALTER,DROP等),可以建立DDL触发器
--为了记载DDL事件信息,应该建立专门的表,以便存放DDL事件信息
create table event_ddl(
event varchar2(20),username varchar2(10),
owner varchar2(10),objname varchar2(20),
objtype varchar2(10),time date);

--注意,当建立DDL触发器时,必须要使用AFTER关键字
CREATE OR REPLACE TRIGGER tr_ddl
after ddl on haiya1.schema
begin
  insert into event_ddl values(
    ora_sysevent,ora_login_user,ora_dict_obj_owner,
    ora_dict_obj_name,ora_dict_obj_type,sysdate);
end;

--在建立了触发器tr_ddl之后,如果在haiya1方案对象上执行了DDL操作,则会将该信息记载到表event_ddl中
create table bjtemp(cola int);
drop table bjtemp;

select event,owner,objname from event_ddl;

select * from event_ddl;


--管理触发器
--显示触发器信息
select trigger_name,status from user_triggers where table_name='EMP';

select * from user_triggers where table_name='EMP';

--禁止触发器
alter trigger tr_check_sal disable;

--激活触发器
alter trigger tr_check_sal enable;

--禁止或激活表的所有触发器
--如果在表上同时存在多个触发器,那么使用ALTER TABLE命令可以一次禁止或激活所有触发器
alter table emp disable all triggers;
alter table emp enable all triggers;

--重新编译触发器
--当使用ALTER TABLE命令修改表结构(例如增加列、删除列)时,会使得其触发器转变为INVALID状态。
--在这种情况下,为了使得触发器继续生效,需要重新编译触发器
alter trigger tr_check_sal compile;

--删除触发器
drop  trigger tr_check_sal;

 

分享到:
评论

相关推荐

    精通Oracle10编程SQL(1-3)PLSQL基础

    特别是"精通Oracle10编程SQL(13)开发触发器.sql"会详细阐述触发器的创建和使用,触发器是数据库自动执行的程序,通常用于在特定的数据更改事件上执行业务规则。 "精通Oracle10编程SQL(16)使用LOB对象.sql"讲解了...

    精通Oracle 10g SQL和PL SQL.zip

    本资源“精通Oracle 10g SQL和PL SQL.zip”提供了全面的学习指南,帮助用户从基础到高级进阶,掌握这两个重要组件的精髓。 SQL(Structured Query Language)是用于管理关系数据库的标准语言,它允许用户创建、查询...

    《精通Oracle10编程》 PDF

    《精通Oracle10编程》是一本专为数据库管理员和开发者设计的专业书籍,旨在深入解析Oracle 10g数据库系统的各种核心技术和高级特性。Oracle 10g是Oracle公司推出的一个重要版本,它在性能、可扩展性和管理性方面都有...

    Oracle 11g SQL和PL SQL从入门到精通 pdf格式电子书 下载(一)

     本书是专门为oracle应用开发人员提供的sql和pl/sql编程指南。通过学习本书,读者不仅可以掌握oracle常用工具oracle universal installer、net comfiguration assistant、sql developer、sql*plus的作用及使用方法...

    精通Oracle PLSQL编程

    通过阅读《精通Oracle PLSQL编程》这本书,你将有机会掌握这些核心概念,并逐步成为一个熟练的Oracle数据库开发者。书中的实例和练习将帮助你更好地理解和应用这些技术,为你的职业生涯打下坚实的基础。

    《精通Oracle PL/SQL》源码

    《精通Oracle PL/SQL》这本书深入探讨了这个语言的各个方面,旨在帮助读者掌握其精髓并提升在数据库开发中的效率。书中提供的源码示例是学习和理解PL/SQL语法、功能以及最佳实践的重要资源。 在"2174_...

    精通Oracle10g SQL/PL编程.PDF

    总之,《精通Oracle10g SQL/PL编程》是一本全面覆盖Oracle10g数据库管理和开发的教程,无论你是初入数据库领域的新人,还是寻求技术提升的资深开发者,都能从中受益匪浅。通过深入阅读和实践,你将能够熟练运用SQL和...

    精通Oracle10编程

    《精通Oracle10编程》是一本深入探讨Oracle数据库10g版本编程的参考资料,适合对数据库有基础了解并希望进一步提升Oracle技术的读者。Oracle作为全球广泛使用的大型关系型数据库管理系统,其10g版本在功能和性能上都...

    精通oracle10编程 教程 +pl/sql pdf

    本教程的"精通Oracle10编程"部分,将深入讲解如何使用PL/SQL进行数据库交互,包括变量声明、流程控制、异常处理和游标等基本概念。 在PL/SQL编程中,了解SQL DML语句(INSERT、UPDATE、DELETE)是基础,它们用于...

    ORACLE PL/SQL从入门到精通

    ORACLE PL/SQL是从入门到精通的专业知识,涵盖了数据库开发与管理的多个方面,包括触发器、过程、函数、软件包、异常处理、游标、循环、分支、变量使用、数据库安装等关键知识点。 触发器是数据库中用来保证数据...

    精通ORACLE 10G SQL和PL_SQL

    本资源"精通ORACLE 10G SQL和PL_SQL"旨在帮助用户深入理解并熟练掌握这两门语言在实际应用中的技巧。 SQL,全称为结构化查询语言,是用于管理关系数据库的标准语言。在Oracle 10g中,SQL主要分为以下几个部分: 1....

    精通Oracle10g PL_SQL编

    通过学习《精通Oracle10g PL_SQL编程》,你将能够熟练地运用PL/SQL进行数据库应用程序的开发,解决实际工作中遇到的各种问题,从而提升你的数据库管理和编程能力。无论是初学者还是有经验的开发者,都可以从本教程中...

    精通OracleSQL第2版.zip

    《精通Oracle SQL(第2版)》是一本深入解析Oracle数据库查询语言的专业书籍,由Oracle ACE和OakTable团队的专家共同撰写,集成了他们的丰富经验和专业知识。这本书旨在帮助读者掌握Oracle SQL的高级技巧,提升在...

    精通Oracle10编程(从入门到精通).rar

    Oracle数据库是全球最广泛使用的商业关系型数据库管理系统之一,尤其在企业级应用...《精通Oracle10编程》这本书将带领读者逐步探索这个强大的数据库系统,从基础到进阶,为成为数据库管理员或开发人员奠定坚实的基础。

    精通Oracle10g PLSQL编程.rar

    在"精通Oracle10g PLSQL编程"的资料中,你将深入学习到如何有效地使用这一语言进行数据库管理和应用开发。 1. **PLSQL基础** - **变量和数据类型**:理解PLSQL中的基本数据类型,如NUMBER、VARCHAR2、DATE等,并...

    Oracle 11g SQL和PL SQL从入门到精通 pdf格式电子书 下载(二)

     本书是专门为oracle应用开发人员提供的sql和pl/sql编程指南。通过学习本书,读者不仅可以掌握oracle常用工具oracle universal installer、net comfiguration assistant、sql developer、sql*plus的作用及使用方法...

    精通oracle 10g plsql 编程-学习笔记

    ### 精通Oracle 10g PL/SQL编程学习笔记 #### 一、PL/SQL综述 **1.1 PL/SQL的功能与作用** PL/SQL (Procedural Language for SQL) 是一种专门为Oracle数据库设计的过程化语言,它结合了SQL的数据处理能力与过程化...

Global site tag (gtag.js) - Google Analytics