触发器&内置程序包

========================================================

1.触发器(关于触发器的原理要讲清楚)
2.内置程序包

一、触发器
    1.三种操作:  delete   update   insert      
    2.两个临时表:  :new   :old    
    3.两个时间点:   after    before
    4.两种重要模式:  行级    语句级
    5.条件: when

    Oracle中的触发器比SQL Server要复杂;
    SQL Server中增删改操作只会触发一个事件,但在Oracle中会触发两个事件。
    以delete为例,Oracle有个删除前事件 before 、删除后事件 after。
    Oracle触发器分:前触发、后触发

1.什么是触发器?
    (1) 触发器是一种特殊的存储过程;
    (2) 触发器不能被直接调用,也不是手动启动,而是由事件来触发;--增删改
    (3) 触发器经常用于加强数据的完整性约束和业务规则等。
    (4) 触发器具备事务的功能。
    简单点说:触发器就是个开关,负责灯的亮与灭,你动了它就亮了。

    Oracle触发器比SQL Server的要复杂,有触发前before与触发后after。


2.创建触发器语法(史上最难的oracle语法,没有之一)
create [or replace] trigger trigger_name
after|before|instead of                    --instead反向
[insert][[or] update [of 列列表]][[or] delete]
on table表或view                            --视图使用率 
[referencing{:old [as] old/:new [as] new}]  --引用新表老表
[for each row]                              --行级模式
[when(condition)]                           --条件
pl/sql_block;                               --pl/sql语句(begin...end)

insert  after  before


--案例:
insert into emp values(…,张三,…,0,……);

==>去  :new

create or replace trigger trig_name
after insert
on emp
for each row
begin
    if(:new.sal=0) then
    dbms_output.put_line('警告:干活不能不给薪水');
    else
    dbms_output.put_line('已插入记录');
    end if;
end;


3. 触发器组成三部分:
   a. 触发器语句(事件)--定义激活触发器的DML事件和DDL事件;
   b. 触发器限制       ---执行触发器的条件,该条件为真才能激活触发器;
   c. 触发器操作(主体)--包含SQL语句和代码,它们在发出了触发语句且触发限制的值为真是才运行。

   注示:序列通过前触发保存到数据库中。


4. 前触发与后触的原理图


5. 在级联表中创建触发器案例

--李斯文不能删
  (什么时候触发?a.delete时; b.when 条件满足时; c.代码中写明)

create or replace trigger t_studel
after delete
on stuinfo
for each row
begin
    if :old.stuname='李斯文' then
    --抛出异常
    raise_application_error(-20010,'该学生不能删!!!');
    end if;
end;


delete from emp;

--李斯文不能删,不能改
after delete or update

--怎么知道是(insert\delete\update)哪个操作?
……
begin
case
    when deleting then
    --删除时
    if :old.stuname='李斯文' then
        raise_application_error(-20010,'该学生不能删!!!');
        end if;


    when updating then
    --修改时
    if :old.stuname='李斯文' then
        raise_application_error(-20011,'该学生不能修改!!!');
        end if;


    when inserting then
    --插入时
    if :old.stuname='张杨' then
        raise_application_error(-20012,'该学生你也敢招!!!');
        end if;


end case;
end;


insert 李超    :new

insert  before  ---->  if (:old  李超    --->  插入到表中去 ==没用
                       if (:new  李超    --->  没插入到表中

before--->:new


insert  after   ---->  if (:old  李超)   --->  插入到表中去
                   if (:new  李超)   --->  没插入到表中


before | after  insert  ----> :new
before | after  delete  ----> :old


====================================
思考:
一个表能创建几个insert\update\delete触发器?
====================================
高级点的触发器

--多表联接

1.确定触发器写在哪个表上  on table
2.确定使用哪个触发器insert  delete   update
3.用after 还是 before,用:new  :old


--在stuinfo表中写个delete触发器,指定删除的人名,
直接删除stumarks表中该人的成绩。

create or replace tirgger t_mydel
after delete
on stuinfo
for each row
    declare
    stu varchar2(22);
begin
    stu:=:old.stuno; --将删除的学生的学号赋值给该变量
    delete from stumarks where stuno=stu;
end;

--运行下
delete from stuinfo where stuname='李斯文';


============================================
注意:
表连接的触发器是比较复杂的,对A表操作触发A表的触发器,同时影到到了B表触发了B表的触发器,依次类推下去...

建议:表跟表关联频繁时,建议甚用触发器。
============================================

行级触发器与语句级触发器:

--案例2
create or replace tirgger t_mydel
after delete
on stuinfo
for each row
begin
    dbms_output.put_line('删的好!');
end;

--执行(删除了一条记录,结果显示一条'删的好')
delete from stuinfo where stuname='李文才';

--执行(删除了整个表中的记录,显示N条'删的好')
delete from stuinfo

--说明:这就是讲解行级触发器。
--行级触发器:一条条的删,删一条就触发一个行级触发器。

    *********************************
    思考:
    如果将[for each row]代码删除,执行看效果。--语句级触发器。
    *********************************


--语句级触发器:执行一条触发一次。

===========================================

标识列:序列+触发器
    
--创建个新表,准备往里面插入记录,使用触发器和序列。

create table tb_715(
    sid number,
    sname varchar2(22)
)


--执行插入操作
insert into tb_715(sid,sname) values(1,'刘帅')

--需求:不写sid,1能帮我自动产生一个序列。

--解决:(1)创建序列
create sequence seq715;
    (2)创建个触发器,用前触发,用new表
create or replace trigger t_insert
before insert
on tb_715
for each row
begin
    --新表中的id=序列的下一个值
    select seq715.nextval into :new.sid from dual;
end;

*****************************************

oracle 11g的语法:
    :new.sid:=seq715.nextval;

oracle 10g的语法:
    select seq715.nextval into :new.sid from dual;

别用变量,用变量的方法就是11g的写法。

*****************************************


--:new表,将插入的数据先放入到:new表中,确认后放到要更新的表。

--:old表,将不要的数据先放入到:old表中,确认不要了再清除:old表。

--注意::new表和:old表中至始至终就只有一条数据,那请问有多少个列?触发器的表有多少个列,:new表和:old表就有多少个列。

commit;--提交

--oracle-06 触发器
1.触发器关键词:trigger  
2.触发器概述:是一个特殊的存储过程,而存储过程又是一个特殊的函数
3.作用:当执行DML(insert,update,delete)语句时,触发器会被自动触发,不能手动调用
4.触发器的使用场景:
#(1)可以限制数据的插入
#(2)可以限制数据的修改
#(3)可以限制数据的删除
#(4)重点:a.级联删除 b.序列+触发器===》模拟自增长
5.触发器的语法(2322)
#  2: 2个触发时间点:after|before
#  3: 3个触发事件 insert update delete
#  2: 2个触发模式  语句级触发器模式     行级触发器模式(for each row)
#  2: 2个伪表     :new   :old
create or replace trigger 触发器名称
before|after
insert| update|delete
on tableName
for each row
	begin
		--可执行模块:限制数据
		end;
--------------------------------------------------------------------

--创建学生信息表
create table stuInfo
(
  stuNo varchar2(8) not null primary key,
  stuName varchar2(10) not null,
  stuSex varchar2(2) not null,
  stuAge number(6) not null,
  stuSeat number(6) not null,
  strAddress varchar2(255) default('地址不详')
)

go

--创建学生信息表
create table stuInfo
(
  stuNo varchar2(8) not null primary key,
  stuName varchar2(10) not null,
  stuSex varchar2(2) not null,
  stuAge number(6) not null,
  stuSeat number(6) not null,
  strAddress varchar2(255) default('地址不详')
)

go

--创建学生成绩表
create table stuMarks
(
  ExamNo varchar2(7) not null primary key,
  stuNo varchar2(6) not null references stuInfo(stuNo),
  writtenExam number(6) null,
  LabExam number(6) null
)

go

--往学生信息表内插入测试数据
insert into stuInfo(stuNo, stuName, stuSex, stuAge,stuSeat,strAddress)
select 's25301', '张秋丽', '男', 18,1, '北京海淀' from dual union
select 's25303', '李斯文', '女', 22,2, '河阳洛阳' from dual union
select 's25302', '李文才', '男', 85, 3,'地址不详' from dual union
select 's25304', '欧阳俊雄', '男', 28, 4,'新疆' from dual union
select 's25318', '梅超风', '女', 23, 5,'地址不详' from dual

go

--往学生成绩表内插入测试数据
insert into stuMarks(ExamNo, stuNo, writtenExam, LabExam)
select 's271811', 's25303', 93, 59 from dual union
select 's271813', 's25302', 63, 91 from dual union
select 's271816', 's25301', 90, 83 from dual union
select 's271817', 's25318', 63, 53 from dual

go

select * from stuInfo;
select * from stuMarks;

--需求:创建一个触发器,限制学生:康康禁止插入
create or replace trigger t_demo1
after
insert
on stuInfo
for each row
	begin
		--限制康康不能插入
		if (:new.stuName = '康康') then
			--错误窗口提示,阻止DML语句运行成功。raise_application_error(状态码,错误信息);  状态码范围: -20000  -20099
			raise_application_error('-20001','康康不能插入,有污点');		
			end if;
		end;

insert into stuInfo
select 's25366', '康康2', '男', 18,1, '北京海淀' from dual;

select * from stuInfo;
rollback;

--康康2不能删除
create or replace trigger t_demo2
after
delete
on stuInfo
for each row
	begin
		if(:old.stuName = '康康2') then
		      raise_application_error('-20002','康康2不能删除');
					end if;
		end;

delete from stuInfo where stuName = '康康2';


--需求:编写1个触发器,同时限制 康康2不能删除,梅超风不能修改,廖家军不能新增

create or replace trigger t_demo3
after
insert or update or delete
on stuInfo
for each row
begin
	--触发器包含多个限制操作,先判断  触发的是哪一个?
	if inserting then
		if (:new.stuName = '廖嘉俊') then
			raise_application_error('-20004','廖嘉俊不能新增');
		end if;
	elsif deleting then
		if (:old.stuName = '康康2') then
			raise_application_error('-20005','康康2不能删除');
		end if;
  elsif updating then
		if (:old.stuName = '梅超风') then
			raise_application_error('-20006','梅超风不能修改');
		end if;
	end if;
end;
----------------------------------------------------------------
insert into stuInfo
select 's25333', '廖嘉俊', '男', 18,1, '北京海淀' from dual;



--功能:级联删除
select * from stuInfo;
select * from stuMarks;

delete from stuInfo where stuName = '张秋丽';

--利用触发器实现删除主表的数据时,同时将从表的数据删除掉
create or replace trigger t_demo4
after
delete
on Stuinfo
for each row
	begin
		--当触发器被触发时,立刻获取触发器所在表的id  作为条件删除从表的数据
		delete from stuMarks where stuMarks.Stuno = :old.stuno;
		end;

--序列+触发器  模拟标识列   
drop table new_emp;
create table new_emp
as
select empno,ename,sal from emp where 1= 0;

select * from new_emp;
--序列
create sequence s_emp; 
--触发器
create or replace trigger t_emp
before
insert
on new_emp
for each row
	begin
		--当触发器被触发时,获取到当前序列的下一个值立刻赋值给new_emp新表中的id属性
		--oracle 10g
		--select s_emp.nextval into :new.empno from dual;
		--oracle 11g
		:new.empno:=s_emp.nextval;
		end;

--新增数据
insert into new_emp(ename,sal) values('张三',2000)
select * from new_emp;




--行级触发器与语句级触发器
create or replace trigger t_emp
after
insert or update or delete
on new_emp
for each row
  begin
    dbms_output.put_line('ok');
    end;
		
create or replace trigger t_emp2
after
insert or update or delete
on new_emp
  begin
    dbms_output.put_line('okok');
    end;
		
		


select * from new_emp;
update new_emp set ename = '哈哈' where ename = '里斯';


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值