Oracle12C--instead-of触发器(五十六)

  • 在视图上定义替代触发器
    • 定义:对视图进行触发器的定义,被称为替代(instead-of)触发器;
    • 视图的问题:如果定义了一个由多张数据表一起显示的视图,这个时候用户是无法对此视图执行更新或增加数据的操作的;
      • 通过一个示例,说明这个问题:创建一张包含20部门雇员编号、姓名、职位、基本工资、部门编号、部门名称、位置的视图;

CREATE OR REPLACE VIEW v_myview AS

SELECT e.empno , e.ename , e.job , e.sal , d.deptno , d.dname , d.loc

FROM emp e,dept d

WHERE e.deptno=d.deptno AND d.deptno=20 ;

  • 向视图插入一条数据

INSERT INTO v_myview (empno , ename, job , sal , deptno,dname,loc)

VALUES (6688, '魔乐' , 'CLERK' , 2000, 50 , '教学' , '北京') ;

运行结果:

错误报告:

SQL 错误: ORA-01776: 无法通过联接视图修改多个基表

  • 可通过替代触发器对视图所映射的数据表直接及进行操作:
    • Oracle12C--instead-of触发器(五十六)_第1张图片
  • 创建语法:
  • 注意:替代触发器可以解决视图的一些更新操作问题,但对于不可更新的视图依然无法实现操作,当视图中包含了以下的结构之一,就表示为不可更新的视图:
    • 统计函数;
    • CASEDECODE语句;
    • GROUP BY,HAVING子句;
    • DISTINCT消除重复列;
    • 集合运算连接;
  • 实现视图增加数据的替代触发器
    • 说明:因为视图本身由多张数据表查询得来,想实现数据增加,就要将这些增加的数据设置到不同的表中,可用替代触发器完成;
    • 示例1:创建一个INSERT替代触发器,用于执行视图更新操作
      • 分析:
        • 由于此时需要通过视图执行数据增加操作,所以要在替代触发器中实现具体的增加数据操作,分别将要增加的deptemp信息的内容增加到各自对应的数据表中;
        • 由于部门编号增加时有可能重复,所以应该先判断增加视图信息的部门编号是否存在,如果不存在,则保存新的dept信息
      • 代码:

CREATE OR REPLACE TRIGGER view_trigger

INSTEAD OF INSERT ON v_myview

FOR EACH ROW

DECLARE

v_empCount NUMBER ;

v_deptCount NUMBER ;

BEGIN

-- 判断要增加的雇员是否存在

SELECT COUNT(empno) INTO v_empCount FROM emp WHERE empno=:new.empno ;

-- 判断要增加的部门是否存在

SELECT COUNT(deptno) INTO v_deptCount FROM dept WHERE deptno=:new.deptno ;

IF v_deptCount = 0 THEN -- 部门不存在

INSERT INTO dept(deptno,dname,loc) VALUES (:new.deptno , :new.dname , :new.loc) ;

END IF ;

IF v_empCount = 0 THEN

INSERT INTO emp(empno,ename,job,sal,deptno)

VALUES (:new.empno , :new.ename , :new.job , :new.sal , :new.deptno) ;

END IF ;

END ;

/

  • 执行视图增加操作

INSERT INTO v_myview (empno , ename, job , sal , deptno,dname,loc)

VALUES (6688, '微软' , 'CLERK' , 2000, 50 , '教学' , '北京') ;

COMMIT ;

  • 查询emp表中是否存在了新增的6688记录

SELECT * FROM emp WHERE empno=6688 ;

  • 查询dept表中是否存在了新增的50部门记录

SELECT * FROM dept WHERE deptno=50 ;

  • 实现视图修改数据的替代触发器
    • 说明:视图中的数据属于多表数据的集合,在更新时,需要考虑对多张数据表执行更新操作;
    • 示例1:创建一个UPDATE替代触发器

CREATE OR REPLACE TRIGGER view_trigger

INSTEAD OF UPDATE ON v_myview

FOR EACH ROW

BEGIN

UPDATE emp SET ename=:new.empno , job=:new.job , sal=:new.sal WHERE empno=:new.empno ;

UPDATE dept SET dname=:new.dname,loc=:new.loc WHERE deptno=:new.deptno ;

END ;

/

  • 更新视图信息

UPDATE v_myview SET ename='史密思',sal=2000,dname='调研部' WHERE empno=7369 ;

COMMIT ;

  • 查询v_myview视图

SELECT * FROM v_myview ;

查询emp表中7369雇员信息是否被更新

SELECT * FROM emp WHERE empno=7369 ;

  • 查询dept表中20部门的信息是否被更新

SELECT * FROM dept WHERE deptno=20 ;

  • 实现视图删除数据的替代触发器
    • 如果现在执行删除视图的一个操作,并且删除完成之后,执行的部门已经没有任何一名雇员存在,则应该同部门信息一起删除,此时可利用替代变量执行本操作;
    • 示例1:创建一个DELETE替代触发器

CREATE OR REPLACE TRIGGER view_trigger

INSTEAD OF DELETE ON v_myview

FOR EACH ROW

DECLARE

v_empCount NUMBER ;

BEGIN

DELETE FROM emp WHERE empno=:old.empno ;

SELECT COUNT(empno) INTO v_empCount FROM emp WHERE deptno=:old.deptno ;

IF v_empCount = 0 THEN -- 此部门没有雇员

DELETE FROM dept WHERE deptno=:old.deptno ;

END IF ;

END ;

/

  • 删除视图之中所有20部门的雇员

DELETE FROM v_myview WHERE deptno=20 ;

COMMIT ;

删除视图中全部的20部门雇员信息,相当于删除了雇员表中的全部20部门雇员信息,此时20部门已经没有员工了,最后可将20部门雇员的信息也删除

  • 示例2:以上为根据不同DML分开编写替代触发器,也可以将所有功能集中在一个替代触发器中进行编写,此时依然可以使用触发器提供的3个谓词INSERTING,UPDATINGDELETING进行操作的判断
    • 将三个不同功能的替代触发器变为一个替代触发器

CREATE OR REPLACE TRIGGER view_trigger

INSTEAD OF INSERT OR UPDATE OR DELETE ON v_myview

FOR EACH ROW

DECLARE

v_empCount NUMBER ;

v_deptCount NUMBER ;

BEGIN

IF INSERTING THEN

-- 判断要增加的雇员是否存在

SELECT COUNT(empno) INTO v_empCount FROM emp WHERE empno=:new.empno ;

-- 判断要增加的部门是否存在

SELECT COUNT(deptno) INTO v_deptCount FROM dept WHERE deptno=:new.deptno ;

IF v_deptCount = 0 THEN -- 部门不存在

INSERT INTO dept(deptno,dname,loc)

VALUES (:new.deptno , :new.dname , :new.loc) ;

END IF ;

IF v_empCount = 0 THEN

INSERT INTO emp(empno,ename,job,sal,deptno)

VALUES (:new.empno , :new.ename , :new.job , :new.sal , :new.deptno) ;

END IF ;

ELSIF UPDATING THEN

UPDATE emp SET ename=:new.empno , job=:new.job , sal=:new.sal WHERE empno=:new.empno ;

UPDATE dept SET dname=:new.dname,loc=:new.loc WHERE deptno=:new.deptno ;

ELSIF DELETING THEN

DELETE FROM emp WHERE empno=:old.empno ;

SELECT COUNT(empno) INTO v_empCount FROM emp WHERE deptno=:old.deptno ;

IF v_empCount = 0 THEN -- 此部门没有雇员

DELETE FROM dept WHERE deptno=:old.deptno ;

END IF ;

ELSE

NULL ;

END IF ;

END ;

/

  • 分析:此程序完成了与之前3个触发器同样的操作;

你可能感兴趣的:(Oracle,Oracle12c学习笔记)