zoukankan      html  css  js  c++  java
  • 触发器详解

    1. 触发器的概念:

    触发器是存储在服务器中的程序单元,当数据库中某些事件发生时(比如insertupdatedelete),数据库自动启动触发器,执行触发器中的相应操作。

    (1) 触发器是一种特殊的存储过程,具备事务的功能;

    (2) 触发器不能被直接调用,而是由事件来触发;--例如:增删改

    (3) 触发器常用于加强数据的完整性约束和业务规则等。

    简单点说:触发器就是个开关,灯就是开关触发后的操作,触动了开关灯就亮了。

    2. 触发事件:

    Insert,update,delete,create(创建对象时),alter,drop

    logon/logoff(用户的登录或注销时执行触发器)

    startup/shutdown(数据库打开或关闭时执行触发器)。

    3. 触发时间

    before 在指定的事件发生之前执行触发器

    after 在指定的事件发生之后执行触发器

    4. 触发级别

    4.1行级触发

    行触发:对触发事件影响的每一行执行触发器,即触发机制是基于行的。改一行数据,触发一次。

    关键语句:for each row

    --案例1

    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

    --说明:这就是讲解行级触发器。

    --行级触发器:一条条的删,删一条就触发一个行级触发器。

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

    4.2语句触发

    语句触发:对触发事件只能触发一次,而且不能该问受触发器影响的每一行的值。既无论这条SQL语句影响多少条记录,触发器都只触发一次。

    4.2.1. 创建触发器

    create [or replace] trigger trigger_name

    after|before|instead of --instead反向

    [insert][[or] update [of 列列表]][[or] delete]

    on table表或view

    [for each row] --行级模式

    Begin

    --pl/sql语句(begin...end)

    End;

    案例1:

    --创建一个触发器tig_1,当用户删除scott.emp表中的数据时提示。

    SQL>create or replace trigger tig_1

    after delete

    on scott.emp //注意:这里没有用for each row,即不管删除多少条,只触发一次该触发器

    begin

    if deleting then

    dbms_output.put_line('有用户删除了emp表中的数据!');

    end if;

    end;

    案例2:

    --创建一个触发器tig_2,当表scott.dept中的deptno列的值发生变化时,自动更新表scott.emp中的deptno列的值,从而保证数据的完整性。

    SQL>create or replace trigger tig_2

    after update

    on scott.emp

    for each row

    begin

    update scott.emp set deptno = :new.deptno

    where deptno = :old.deptno;

    end;

    注意:

    这段程序中有两个概念:new和:old, :new代表执行更新操作之后的新表,:old代表执行更新操作之前的旧表。

    通过这两张表的使用,可以访问到触发器执行前后表数据的变化。

    insert操作只有:new,delete操作只有:old,update操作二者皆有。

    :new 和 :old只用于行级触发器。

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

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

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

    --案例:

    SQL>insert into emp values(…,张三,…,0,……);

    SQL>create or replace trigger trig_name

    after insert --插入操作之后

    on emp --在emp表中

    for each row --行级模式

    begin

    if(:new.sal<=0) then --新表:new中的sal等于0

    dbms_output.put_line('警告:干活不能不给薪水');

    rollback;(可以用异常:抛异常后回滚数据)

    else

    dbms_output.put_line('已插入记录');

    commit;

    end if;

    end;

    5.触发器组成三部分:

    a. 触发器语句(事件)--定义激活触发器的DML事件和DDL事件;

    b. 触发器限制 --执行触发器的条件,该条件为真才能激活触发器;

    c. 触发器操作(主体)--包含SQL语句和代码,它们在发出了触发语句且触发限制的值为真是才运行。

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

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

    --李斯文不能删

    (什么时候触发?a.delete时; b.when 条件满足时; c.代码中写明)

    SQL>create or replace trigger t_studel

    after delete --删除操作之后

    on stuinfo

    for each row

    begin

    if :old.stuname='李斯文' then --如果:old表中存在李斯文,就提示不能删

    --抛出异常

    raise_application_error(-20010,'该学生不能删!!!');

    end if;

    end;

    SQL>delete from emp;

    --李斯文不能删也不能改

    只需修改上例代码中的:

    ……

    after delete or update

    ……

    --怎么知道是(insertdeleteupdate)哪个操作?不知道没关系,用case when语句

    ……

    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 :new.stuname='张杨' then

    raise_application_error(-20012,'该学生你也敢招!!!');

    end if;

    end case;

    end;

    6.多表连接触发器

    在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='李斯文';

    7. 触发器的应用(标识列):

    标识列:序列+触发器

    --解决:

    (1)建表

    create table tb_715(

    sid number,

    sname varchar2(22)

    )

    (2)创建序列

    create sequence seq715;

    (3)创建个触发器,用前触发,用new表

    create or replace trigger t_insert

    before insert

    on tb_715

    for each row

    begin

    --新表中的id=序列的下一个值

    :new.sid:=seq715.nextval;

    end;

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

    oracle 11g的语法:

    :new.sid:=seq715.nextval;

    oracle 10g的语法:

    select seq715.nextval into :new.sid from dual;

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

    Oracle触发器分:前触发、后触发

  • 相关阅读:
    刚搬过了,请大家多多支持!!
    [导入]搞到了visual studio 2005 professional edtion
    一些常用的正则表达式
    xinxp的隐藏技巧
    今天领准考证了
    推荐一本.net的好书
    今天装上Linux了
    隐藏在Windows XP中的28个秘密武器
    为 Sharepoint 创建可视的 WebPart
    在 NHibernate 中一切必须是 Virtual 的吗?
  • 原文地址:https://www.cnblogs.com/kcwang/p/14881817.html
Copyright © 2011-2022 走看看