当前位置: 首页 > 编程日记 > 正文

PL/SQL -- INSTEAD OF 触发器

为什么80%的码农都做不了架构师?>>>   hot3.png

--==============================

-- PL/SQL --> INSTEAD OF 触发器

--==============================

 

    INSTEAD OF 触发器常用于管理编写不可更新的视图,INSTEAD-OF触发器必须是行级的。

    可以用INSTEAD OF触发器来解释INSERTUPDATEDELETE语句,并用备用的程序代码替换那些指令。

 

一、不可更新视图

    基于下列情形创建的视图,不可直接对其进行DML操作

        使用了集合操作运算符(UNION,UNION ALL ,INTERSECT,MINUS)

        使用了分组函数(MIN,MAX,SUM,AVG)

        使用了GROUP BY ,CONNECT BY ,START WITH 子句

        使用了DISTINCT 关键字

        使用了连接查询

      对于基于上述情况创建的视图,不能对其直接执行DML,但可以在该视图上创建INSTEAD OF触发器来间接执行DML

   

二、创建INSTEAD OF 触发器的语法

    CREATE [OR REPLACE] TRIGGER trigger_name

    INSTEAD OF {dml_statement }

    ON {object_name | database | schema}

    FOR EACH ROW

    [WHEN (logical_expression)]

    [DECLARE]

        declaration_statements;

    BEGIN

        execution_statements;

    END [trigger_name];

    /

 

三、创建视图

    --在下面创建的视图中,由于使用了连接查询,因此视图将不可更新

        CREATE OR REPLACE VIEW vw_dept_emp

        AS

          SELECT deptno,d.dname,e.empno,e.ename

          FROM dept d

          JOIN emp e

          USING (deptno);

   

    --从数据字典(user_updatable_columns)中查询某一视图哪些列是可更新或不可更新的

        scott@ORCL> col owner format a15

        scott@ORCL> select * from user_updatable_columns where table_name='VW_DEPT_EMP'; 

 

        OWNER           TABLE_NAME                     COLUMN_NAME     UPD INS DEL

        --------------- ------------------------------ --------------- --- --- ---

        SCOTT           VW_DEPT_EMP                    DEPTNO          YES YES YES

        SCOTT           VW_DEPT_EMP                    DNAME           NO  NO  NO   --可以看到列DNAME不能执行DML

        SCOTT           VW_DEPT_EMP                    EMPNO           YES YES YES

        SCOTT           VW_DEPT_EMP                    ENAME           YES YES YES

         

    --尝试更新视图时,更新失败

        scott@ORCL> update vw_dept_emp set dname='Developement' where deptno=10;

        update vw_dept_emp set dname='Developement' where deptno=10

                               *

        ERROR at line 1:

        ORA-01779: cannot modify a column which maps to a non key-preserved table      

     

        scott@ORCL> update vw_dept_emp set ename='Henry' where empno=7369;

 

        1 row updated.

 

        scott@ORCL> select empno,ename,job from emp where empno=7369;

 

             EMPNO ENAME      JOB

        ---------- ---------- ---------

              7369 Henry      CLERK

     

    --创建一个基于UPDATE INSTEAD OF 触发器

        CREATE OR REPLACE TRIGGER tr_vw_dept_emp

        INSTEAD OF UPDATE

        ON vw_dept_emp

        FOR EACH ROW

        BEGIN

          UPDATE dept

          SET dname=:new.dname

          WHERE deptno=:old.deptno;

        END;

 

    --更新视图

        scott@ORCL> update vw_dept_emp set dname='Developement' where deptno=20;

 

        4 rows updated.

   

    --验证更新后的结果

        scott@ORCL> select * from vw_dept_emp where rownum<2 and deptno=20;

 

            DEPTNO DNAME               EMPNO ENAME

        ---------- -------------- ---------- ----------

                20 Developement         7369 Henry

 

        scott@ORCL> select * from dept where deptno=20;

 

            DEPTNO DNAME          LOC

        ---------- -------------- -------------

                20 Developement   DALLAS     

 

四、INSTEAD OF触发器的应用

    在工作中,有时候需要将两个或多个表中的字段进行同步的问题。即假定有表AB,表A中的字段COLa和表B中的字段COLb需要时时保持同

    步,当表ACOLa被更新时,需要将更新的内容同步到表BCOLb中,反之,当表BCOLb被更新时,需要将COLb的内容更新到A表的COLa中。

    对于这样的问题,按照一般的想法是在表A和表B分别创建触发器来使之保持同步,但实际上表A和表B上的触发器将会被迭代触发,即A表的

    更新将触发B表上的触发器,而B表上的触发器反过来又触发A上的触发器,最终的结果是导致变异表的产生。基于此,我们可以使用INSTEAD

    OF 触发器完成此项任务,下面给出全部过程。

   

    --分别创建表tb_a,tb_b并插入记录

        scott@ORCL> create table tb_a(ID int,COLa varchar2(40));

 

        scott@ORCL> create table tb_b(ID int,COLb varchar2(40));

 

        scott@ORCL> insert into tb_a select 1,'Robinson' from dual;

 

        scott@ORCL> insert into tb_b select 1,'Jackson' from dual;

 

        scott@ORCL> commit;

 

    --在表tb_a上创建触发器

        CREATE OR REPLACE TRIGGER tr_tb_a

          BEFORE UPDATE ON tb_a

          FOR EACH ROW

        DECLARE

          lv_newcol    VARCHAR2(40);

          lv_oldcol    VARCHAR2(40);

        BEGIN

          lv_newcol := :new.COLa;

          lv_oldcol := :old.COLa;

          IF lv_newcol <> lv_oldcol THEN

            UPDATE tb_b

               SET COLb = :new.COLa

             WHERE ID = :new.ID;

          END IF;

          DBMS_OUTPUT.PUT_LINE(lv_oldcol ||'=>'|| lv_newcol);

        END;

   

    --更新表tb_a时,表tb_b的字段也被更新

        scott@ORCL> update tb_a set COLa='Willson' where ID=1;

        Robinson=>Willson

 

        scott@ORCL> select * from tb_b;

 

                ID COLB

        ---------- ----------------------------------------

                 1 Willson

 

    --在表B上创建触发器

        CREATE OR REPLACE TRIGGER tr_tb_b

          BEFORE UPDATE ON tb_b

          FOR EACH ROW

        DECLARE

          lv_newcol    VARCHAR2(40);

          lv_oldcol    VARCHAR2(40);

        BEGIN

          lv_newcol := :new.COLb;

          lv_oldcol := :old.COLb;

          IF lv_newcol <> lv_oldcol THEN

            UPDATE tb_a

               SET COLa = :new.COLb

             WHERE ID = :new.ID;

          END IF;

          DBMS_OUTPUT.PUT_LINE(lv_oldcol ||'=>'|| lv_newcol);

        END;

   

    --更新表tb_b时,出现了表变异的提示,同样更新表tb_a时也会出现类似的提示

        scott@ORCL> update tb_b set COLb='Other'where ID=1;

        update tb_b set COLb='Other'where ID=1

               *

        ERROR at line 1:

        ORA-04091: table SCOTT.TB_B is mutating, trigger/function may not see it

        ORA-06512: at "SCOTT.TR_TB_A", line 8

        ORA-04088: error during execution of trigger 'SCOTT.TR_TB_A'

        ORA-06512: at "SCOTT.TR_TB_B", line 8

        ORA-04088: error during execution of trigger 'SCOTT.TR_TB_B'

 

    --禁用触发器

        scott@ORCL> alter trigger tr_tb_a disable;

 

        scott@ORCL> alter trigger tr_tb_b disable;

 

    --分别在表tb_atb_b上创建视图

        scott@ORCL> create view vw_tb_a as select * from tb_a;

 

        scott@ORCL> create view vw_tb_b as select * from tb_b;

   

    --基于视图vw_tb_a创建instead of 触发器

        CREATE OR REPLACE TRIGGER tr_vw_tb_a

          INSTEAD OF UPDATE ON vw_tb_a

          FOR EACH ROW

        DECLARE

          lv_newcol    VARCHAR2(40);

          lv_oldcol    VARCHAR2(40);

        BEGIN

          lv_newcol := :new.COLa;

          lv_oldcol := :old.COLa;

          IF lv_newcol <> lv_oldcol THEN

            UPDATE tb_a

             SET COLa = :new.COLa

            WHERE ID = :new.ID;

           

            UPDATE tb_b

              SET COLb = :new.cola

            WHERE ID=:new.ID;

          END IF;

          DBMS_OUTPUT.PUT_LINE(lv_oldcol ||'=>'|| lv_newcol);

        END;

   

    --基于视图vw_tb_b创建instead of 触发器

        CREATE OR REPLACE TRIGGER tr_vw_tb_b

          INSTEAD OF UPDATE ON vw_tb_b

          FOR EACH ROW

        DECLARE

          lv_newcol    VARCHAR2(40);

          lv_oldcol    VARCHAR2(40);

        BEGIN

          lv_newcol := :new.COLb;

          lv_oldcol := :old.COLb;

          IF lv_newcol <> lv_oldcol THEN

            UPDATE tb_a

             SET COLa = :new.COLb

            WHERE ID = :new.ID;

           

            UPDATE tb_b

              SET COLb = :new.colb

            WHERE ID=:new.ID;

          END IF;

          DBMS_OUTPUT.PUT_LINE(lv_oldcol ||'=>'|| lv_newcol);

        END;   

   

    --对视图进行更新,验证成功

        scott@ORCL> update vw_tb_a set COLa='Many' where ID = 1;

        Willson=>Many

 

        scott@ORCL> select * from tb_b;

 

                ID COLB

        ---------- ----------------------------------------

                 1 Many

 

        scott@ORCL> update vw_tb_b set COLb='Much' where ID = 1;

        Many=>Much

 

        scott@ORCL> select * from tb_a;

 

                ID COLA

        ---------- ----------------------------------------

                 1 Much

   

五、总结

    视图创建时未指定WITH CHECK OPTION选项

    INSTEAD OF触发器只适用于视图

    基于视图的INSTEAD OF触发器不能指定BEFOREAFTER选项

    INSTEAD OF触发器,必须指定FOR EACH ROW

    当创建的视图被重新定义之后,基于视图上创建的触发器将需要重新定义

 

六、更多参考

有关SQL请参考

        SQL 基础--> 子查询

        SQL 基础-->多表查询

SQL基础-->分组与分组函数

SQL 基础-->常用函数

SQL 基础--> ROLLUP与CUBE运算符实现数据汇总

SQL基础-->层次化查询(START BY ... CONNECT BY PRIOR)

 

    有关PL/SQL请参考

        PL/SQL --> 语言基础

PL/SQL --> 流程控制

PL/SQL --> 存储过程

PL/SQL --> 函数

PL/SQL --> 游标

PL/SQL -->隐式游标(SQL%FOUND)

PL/SQL --> 异常处理(Exception)

PL/SQL --> PL/SQL记录

PL/SQL --> 包的创建与管理

PL/SQL --> 包重载、初始化

PL/SQL --> DBMS_DDL包的使用

PL/SQL --> DML 触发器

PL/SQL --> INSTEAD OF 触发器

   


原文链接: http://blog.csdn.net/robinson_0612/article/details/6098263

转载于:https://my.oschina.net/dtec/blog/47328

相关文章:

开源!《AI 算法工程师手册》中文教程正式发布!

作者 | 红色石头转载自 AI有道&#xff08;id&#xff1a;redstonewill)最近红色石头在浏览网页的时候&#xff0c;偶然发现一份非常不错的 AI 资源&#xff0c;就是这本《AI 算法工程师手册》 。本文将给大家推荐这本优秀教材&#xff0c;并作详细的介绍。这本《AI 算法工程师…

shell中的函数shell中的数组告警系统需求分析

2019独角兽企业重金招聘Python工程师标准>>> 20.16/20.17 shell中的函数 函数的概念 函数就是把一段代码整理到了一个小单元中&#xff0c;并给这个小单元起一个名字&#xff0c;当用到这段代码时直接调用这个小单元的名字即可。 格式: 函数名称() {command} 注&am…

【Live555】live555源码详解(一):BasicUsageEnvironment、UsageEnvironment

【Live555】live555源码详解系列笔记 类关系图 1、UsageEnvironment 详解 1.1 BasicUsageEnvironment BasicUsageEnvironment 继承自 BasicUsageEnvironment0,主要增加的功能,使用静态函数 createNew 来创建自己;重载“<<”操作符,用来向标准错误输出(stderr)打…

Web前端开发人员和设计师必读文章推荐【系列七】

这篇文章主要收录了十二月份发布在梦想天空的优秀文章&#xff0c;特别推荐给Web开发人员和设计师阅读。梦天空博客关注前端开发技术&#xff0c;展示最新 HTML5 和 CSS3 技术应用&#xff0c;分享实用的 jQuery 插件&#xff0c;推荐优秀的网页设计案例&#xff0c;共享精美的…

【Live555】live555源码详解(二):BasicHashTable、DelayQueue、HandlerSet

【Live555】live555源码详解系列笔记 3、BasicHashTable 哈希表 协作图: 3.1 BasicHashTable BasicHashTable 继承自 HashTable 重载 HashTable 接口 Add :添加键值对 Remove :删除键值 Lookup :由“健”查找“值” numEntries :键值对数量重载 HashTable 成员(…

对标英伟达,依图发布AI芯片“求索”

作者 | 一一出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;依图成立 7 年&#xff0c;这次专为芯片召开了第一次产品发布会。5 月 9 日上午&#xff0c;依图科技在上海发布了其首款自研云端视觉推理 AI 芯片“求索”questcore™&#xff0c;以及基于该芯片构建的软硬…

JUC原子类 1

根据修改的数据类型&#xff0c;可以将JUC包中的原子操作类可以分为4类。1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ; 2. 数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray ; 3. 引用类型: AtomicReference, AtomicStampedRerence, AtomicM…

使用ROW_NUMBER 和partition by 解决报表中的查询问题

在报表中遇到一个查询问题&#xff1a; 原始数据如下: Id cust_id call_date call_result 1 1 2012-03-15 09:00:00 fail 2 1 2012-03-15 09:05:00 number error 3 1 2012-03-15 09:10:00 fail 4 1 2012-03-15 09:15:00 success 5 2 2012-03-15 09:01:00 fail …

中国AI开发者真实现状:写代码这条路,会走多久?

2016 年起&#xff0c;人工智能成为中国开发者重点关注的技术领域&#xff0c;以深度学习驱动的计算机视觉、自然语言处理、语音相关技术成为渗透最广的三个 AI 技术领域。然而&#xff0c;在这样的背景下&#xff0c;AI 仍是一个非常前沿的学科&#xff0c;对于中国开发者而言…

linux学习-awk工具

awk是基于列的文本处理工具&#xff0c;它的工作方式是按行读取文本并视为一条记录&#xff0c;每条记录以字段分割成若干字段&#xff0c;然后输出个字段的值&#xff0c;事实上&#xff0c;awk是一种编程语言。awk认为文件都是结构化的&#xff0c;也就是说由单词和各种空白字…

【Live555】live555源码详解(四):Medium媒体基础类

【Live555】live555源码详解系列笔记 7、Media Medai所依赖关系图 依赖Medai关系图 Media和UsageEnvironment关联图

linux中普通文件和块设备文件的区别

1&#xff0c;概述 一直都搞不明白普通文件跟块文件的区别&#xff0c;总觉得一个普通的文件是存放在磁盘块上&#xff0c;那它既属于普通文件又属于块设备文件。刚好下午睡了一个大头觉&#xff0c;比较清醒&#xff0c;集中学习了下普通文件和块设备文件的区别和联系。 本文从…

我的vim配置

我的vim配置 1.通用配置 vimrc 2.自己配置 1.新建.c,.h,.sh,.java文件&#xff0c;自动插入文件头 vim ~/.vim_runtime/my_configs.vim 输入一下内容 """""""""""""""""""&qu…

【Live555】live555源码详解(五):MediaSource、MediaSink、MediaSession、MediaSubsession

【Live555】live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的四个类所在的位置: MediaSource、MediaSink、MediaSession、MediaSubsession 8、MediaSource MediaSource 继承自 Medium,下面是MediaSource的协作图 关于 MediaSource 类的继承关系 …

BAT携手清华、复旦、上交齐聚杭州, 和500名开发者干点啥?

2016 年起&#xff0c;人工智能成为中国开发者重点关注的技术领域&#xff0c;以深度学习驱动的计算机视觉、自然语言处理、语音相关技术成为渗透最广的三个 AI 技术领域。然而&#xff0c;在这样的背景下&#xff0c;AI 仍是一个非常前沿的学科&#xff0c;对于中国开发者而言…

MOS2010开发基础和集几种开发模型

基础 基本的部署结构图类似如下 创建新的Web Application的原因&#xff1a; One key reason to create a new web application is to isolate content. Every time a new web application is created, SharePoint creates a new content database. All the data in the sites …

还在用Matplotlib? 又一可视化神器Altair登场 | 技术头条

作者 | Fernando Irarrzaval 翻译 | Monanfei责编 | Jane出品 | Python 大本营&#xff08;id&#xff1a;pythonnews&#xff09;【导语】如何将我们的数据以更好的形势呈现出来&#xff1f;擅长不同编程语言的程序员会选择各自技术范畴内成熟、好用的工具包&#xff0c;比如 …

【Live555】live555源码详解(六):FramedSource、RTPSource、RTPSink

【Live555】live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的三个类所在的位置: FramedSource、RTPSource、RTPSink 11、FramedSource FramedSource 继承自 MediaSource,下面是实现 FramedSource 的依赖关系图 使用 FramedSource 的关系图

maven在idea的配置

首先去官网下载如图&#xff1a; 下载之后解压打开如图&#xff1a; 配置&#xff1a;1、打开conf文件夹下的settings.xml&#xff08;我用的notepad&#xff09; 第55行左右加上图上的第150行左右在标签下面写上如图&#xff08;阿里提供的存架包的仓库&#xff09; 2、配置id…

Apache下实现禁止目录浏览

当我们访问某个网站时&#xff0c;在后面增加相应的目录&#xff0c;就可以浏览到目录&#xff0c;对于网站来说&#xff0c;是很不安全的。 解决办法&#xff1a;1、编辑httpd.conf文件vi ./conf/httpd.conf找到如下内容&#xff1a;......<Directory "C:/Program Fi…

【Live555】live555源码详解(七):GenericMediaServer、RTSPServer、RTSPClient

【Live555】live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的三个类所在的位置: GenericMediaServer、RTSPServer、RTSPClient 14、GenericMediaServer GenericMediaServer 继承自 Medium,依赖关系图如下: 使用 GenericMediaServer 的关系图:

200万?程序员刚拿下华为Offer,这些技巧你必须知道!

最近&#xff0c;有华为员工在匿名社交网站上&#xff0c;曝光自己年收入已突破200万&#xff01;消息一出&#xff0c;不知酸了多少中国程序员&#xff01;但是&#xff0c;在羡慕之余&#xff0c;我们不如利用起碎片时间&#xff0c;从点滴做起&#xff0c;背水一战&#xff…

有效快速的学习微信小程序

微信小程序 实现了应用“触手可及”的梦想&#xff0c;用户扫一扫或搜一下即可打开应用。不用安装&#xff0c;即开即用&#xff0c;用完就走。省流量&#xff0c;省安装时间&#xff0c;不占用桌面。对用户使用上来说&#xff0c;确实方便&#xff0c;没有繁琐的注册&#xff…

Delphi开发的IOCP测试Demo以及使用说明。

Delphi开发的IOCP&#xff0c;此为压力测试Demo和使用说明。

【Live555】live555源码详解(八):testRTSPClient

【Live555】live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的testRTSPClient实现的三个类所在的位置: ourRTSPClient、StreamClientState、DummySink 1、流程分析 1.1 设置使用环境 创建任务调度器和使用环境 TaskScheduler* scheduler = BasicTask…

ICML 2019:序列到序列自然语言生成任务超越BERT、GPT!微软提出通用预训练模型MASS | 技术头条...

来源 | 微软研究院AI头条&#xff08;id&#xff1a;MSRAsia&#xff09;责编 | Jane编者按&#xff1a;从2018年开始&#xff0c;预训练&#xff08;pre-train&#xff09; 毫无疑问成为NLP领域最热的研究方向。借助于BERT和GPT等预训练模型&#xff0c;人类在多个自然语言理解…

linux 命令详解 二十七

4. 循环语句: Bash Shell中主要提供了三种循环方式&#xff1a;for、while和until。 for循环声明格式&#xff1a; for variable in word_list do command done 见如下示例脚本&#xff1a; /> cat > test7.sh for score in math engl…

【Live555】live555源码详解系列笔记

【Live555】liveMedia下载、配置、编译、安装、基本概念 【Live555】live555源码详解(一):BasicUsageEnvironment、UsageEnvironment 【Live555】live555源码详解(二):BasicHashTable、DelayQueue、HandlerSet 【Live555】live555源码详解(三):Groupsock 【Live555】l…

android 每个块半径不同的扇形图,自定义view

1.首先看效果图 2.自定义PieChartView&#xff0c;继承自View&#xff0c;下边为PieChartView代码 package com.yingjinbao.im.peach.customview;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint…

人工智能的浪潮中,知识图谱何去何从?

漆桂林认为&#xff0c;目前知识图谱整个领域最关注的问题还是如何能够高效、低成本构建知识图谱&#xff0c;而这个问题对于研究人员来说&#xff0c;仍是一个非常大的挑战&#xff0c;比如现在大家都在关注如何在少量甚至无标注场景下进行知识图谱构建。 记者 | Jane 责编 |…