zoukankan      html  css  js  c++  java
  • oracle触发器

    触发器可以看做一种“特殊”的存储过程,它定义了一些与数据库相关事件(INSERT,UPDATE,CREATE)发生时应执行的“功能代码块”,通常用于管理复杂的完整性约束,或监控对表的修改,或通知其他程序,甚至可以实现对数据的审计功能。

    触发事件:能够引起触发器运行的操作被称为“触发事件”,如执行DML(INSERT,UPDATE,DELETE),DDL(CREATE,ALTER.DROP);引发数据库系统事件(系统启动或退出,产生异常错误);引发用户事件(登陆或退出数据库操作)

    根据触发器的触发事件和触发器的执行情况,Oracle所支持的触发器分为一下5种类型:

    1行级触发器:当DML语句对每一行数据进行操作时都会引起该触发器的运行

    2语句级触发器:无论DML语句影响多上行数据,其所引起的触发器仅执行一次

    3替换触发器:该触发器是定义在视图上的,而不是定义在表上,它是用来替换所使用实际语句的触发器

    4用户事件触发器:与DDL操作或用户登陆、退出数据库事件相关的触发器。

    5.系统事件触发器:指Oracle数据库系统的事件中进行触发的触发器,如Oracle实例的启动与关闭

    语句级触发器

    例子:在SCOTT模式下,创建dept_log数据表,并在其中定义两个字段,分别用来存储操作种类信息和操作日期:

    create table dept_log
    (
    operate_tag varchar2(10),
    operate_tiem date
    );

    创建一个关于emp表的语句级触发器,将用户对dept表的操作信息保存到dept_log表中:

    create or replace trigger tri_dept
    before insert or update or delete
    on dept
    declare
    var_tag varchar2(10);
    begin
    if inserting then
    var_tag:='插入';
    elsif updating then
    var_tag:='修改';
    elsif deleting then
    var_tag:='删除';
    end if;
    insert into dept_log
    values(var_tag,sysdate);
    end tri_dept;
    /

    执行触发器,也就是触发这些事件(insert,update,delete);之后再查看dept_log表就可以观察到结果

    行级触发器

    例子 :在SCOTT模式下,创建一个用于存储商品种类的数据表,其中包括商品序号列和商品名称列:

    create table goods(

    id int primary key,

    good_name varchar2(50));

    创建一个序列:

    create sequence seq_id;

    创建一个触发器,用于为goods表的id赋值

    create or replace trigger tri_insert_good
    before insert
    on goods
    for each row
    begin
    select seq_id.nextval
    into :new.id
    from dual;
    end;
    /

    :new.id--列标识符

      有两种列标识符,

      原值标识符:--:old.id --一般在update delete

      新值标识符:--:new.id--一般在update insert

    触发该触发器:

    可以通过插入语句 insert into goods(good_name) values('苹果');

    同时用insert into goods(id,good_name)values (9,'葡萄');

    然后再查询该表即可知道是否,自动插入了id

    但是第二条记录的id,还是会顺序增长,那是因为,触发器将seq_id的nextval值赋给了:new.id,并且nextval属性值是连续不间断的

    替换触发器

    例子:首先创建一个视图

    (首先该用户要有创建视图的权限,切换到system ,grant create view to scott)

    create view view_emp_dept
    as
    select empno,ename,dept.deptno,dname,job,hiredate from emp,dept
    where emp.deptno=dept.deptno;

    注意:在没有创建“替换触发器”时,试图向该视图中插入数据,是会有错误的ORA-01776:无法通过连接视图修改多个基表

    创建一个关于view_emp_dept视图的替换触发器,在该触发器的主体中实现向emp表和dept表中插入两行相互关联的数据

    create or replace trigger tri_insert_view
    instead of insert
    on view_emp_dept
    for each row
    declare
    row_dept dept%rowtype;
    begin
    select * into row_dept from dept where deptno=:new.deptno;
    if sql%notfound then

    insert into dept(deptno,dname) values(:new.deptno,:new.dname);
    end if;
    insert into emp(empno,ename,deptno,job,hiredate) values
    (:new.empno,:new.ename,:new.deptno,:new.job,:new.hiredate);
    end tri_insert_view;
    /

    触发该触发器:

    insert into view_emp_dept(empno,ename,deptno,dname,job,hiredate)

    values(8888,'东方',10,'ACCOUTNTING','CASHIER',sysdate);

    这样,便可以插入一条记录到视图;

    但是,如果这个deptno不在dept表中,那么会在dept表中插入相关记录,但是,测试时,却出现了错误

    用户事件触发器

    因进行DDL操作或用户登录、退出操作而引起运行的一种触发器,比如CREATE,ALTER,DROP,ANALYZE,COMMENT,GRANT,REVOKE,RENAME,TRUNCATE,SUSPEND,LOGON ,LOGOFF

    创建一个日志信息表,用于保存DDL操作的信息,包括数据对象,数据对象类型,操作行为,操作用户,操作日期

    create table ddl_oper_log
    (
    db_obj_name varchar2(20),
    db_obj_type varchar2(20),
    oper_action varchar2(20),
    oper_user varchar2(20),
    oper_date date);

    关于scott用户的DDL操作(CREATE,ALTER,DROP),创建一个触发器,然后将DDL操作的相关信息插入到ddl_oper_log日志表中

    create or replace trigger tri_ddl_oper
    before create or alter or drop
    on scott.schema
    begin
    insert into ddl_oper_log values(
    ora_dict_obj_name,--获取DDL操作对象的名称
    ora_dict_obj_type,--获取DDL操作所对应的数据库对象的类型
    ora_sysevent,--获取触发器的系统事件名称
    ora_login_user,--获取登陆用户名
    sysdate);
    end;
    /

    触发触发器:

    create,alter,drop 然后再select * from ddl_oper_log;

    例子:

    CREATE OR REPLACE PACKAGE aae AS
    TYPE cur_sor IS REF CURSOR;--声明一个cursor的游标

    PROCEDURE showsalsu(dept_id NUMBER,ab OUT CUR_SOR);

    END aae;(程序包)

    CREATE OR REPLACE PACKAGE BODY aae AS
    PROCEDURE showsalsu(dept_id NUMBER,ab OUT CUR_SOR)AS
    a employees%ROWTYPE;
    BEGIN
    OPEN ab FOR SELECT * FROM employees e WHERE e.department_id=dept_id;打开游标并把值给游标

    LOOP
    FETCH ab INTO a ;--取值
    EXIT WHEN ab%NOTFOUND;
    dbms_output.put_line(a.last_name);

    END LOOP;
    END;
    END aae;

  • 相关阅读:
    Leetcode中级算法-二分查找01
    二叉查找树01(c++代码实现)
    Leetcode中级算法-动态规划03(最长上升子序列)
    Leetcode中级算法-动态规划02
    Leetcode中级算法-动态规划01
    Leetcode中级算法-全排列
    使用git获取Linux内核
    Kali 使用proxychains接管全局代理
    kali2020.1安装问题解决【选择并安装软件】
    unzip最常用使用方法
  • 原文地址:https://www.cnblogs.com/gaofangquan/p/7382846.html
Copyright © 2011-2022 走看看