MERGE 函数的使用[通俗易懂]

MERGE 函数的使用[通俗易懂]1.Merge是什么?

大家好,又见面了,我是你们的朋友全栈君。

1. MERGE是什么?

    通过一个简单的需求来了解MERGE 是什么?

    从T1表更新数据到T2表,如果T2表NAME字段的记录在T1表中存在,就将MONEY字段的值累加,

    如果不存在,将T1表的记录插入到T2表中。

    CREATE TABLE T1 (NAME VARCHAR2(20),MONEY NUMBER);

    INSERT INTO T1 VALUES (‘A’,10);

    INSERT INTO T1 VALUES (‘B’,20);

    COMMIT;   

    CREATE TABLE T2 (NAME VARCHAR2(20),MONEY NUMBER);

    INSERT INTO T2 VALUES (‘A’,30);

    INSERT INTO T2 VALUES (‘C’,20);

    COMMIT;

    如果按照一般逻辑思路,该需求至少需要UPDATE和INSERT两条SQL语句才能完成,

    但是使用MERGE语句,则可以实现“存在则UPDATE,不存在则INSERT”的逻辑。

 

   MERGE 的语法:

   MERGE INTO table [t.alias]

   USING {table | view | subquery} [t.alias]

   ON (condition)

   WHEN MATCHED THEN

      merge_updat_clause

   WHEN NOT MATCHED THEN

      merge_insert_clause;

  

注:USING后面必须包含要更新或插入的行,可以是表也可以是语句


   则上面的需求我们可以利用MERGE简单的实现:

   MERGE INTO T2

   USING T1

   ON (T1.NAME=T2.NAME)

   WHEN MATCHED THEN

       UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY

   WHEN NOT MATCHED THEN

      INSERT VALUES (T1.NAME,T1.MONEY);

   COMMIT;


2. MERGE的完善

2.1. UPDATE 和 INSERT 动作可只出现其一

      可选择仅更新目标表:

      MERGE INTO T2

      USING T1

      ON (T1.NAME=T2.NAME)

      WHEN MATCHED THEN

         UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY;  

      COMMIT;

      可选择仅插入(INSERT)目标表而不做任何更新(UPDATE)操作:

      MERGE  INTO T2

      USING T1

      ON (T1.NAME=T2.NAME)

      WHEN NOT MATCHED THEN

         INSERT  VALUES (T1.NAME,T1.MONEY);         

      COMMIT;

2.2 可对MERGE语句加条件

      MERGE INTO T2

      USING T1

      ON (T1.NAME=T2.NAME)

      WHEN MATCHED THEN

         UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY

      WHERE T1.NAME=’A’;      — 此处表示对MERGE的条件进行过滤

      COMMIT;

2.3 可用DELETE 子句清除行

      清除行的前提条件是,要找到满足 T1.NAME=T2.NAME 的记录,如果T2.NAME=‘A’并不

      满足T1.NAME=T2.NAME过滤出的记录集,那么 DELETE 是不会生效的,在满足条件的

      前提下,可以删除目标表的记录。

      MERGE INTO T2

      USING T1

      ON (T1.NAME=T2.NAME)

      WHEN MATCHED THEN 

         UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY

      DELETE WHERE (T2.NAME=’A’);

   — DELETE WHERE (T2.NAME=’C’); 虽然 DELETE 语句不生效,但前面的 UPDATE 语句还是生效的

      COMMIT;

2.4 可采用无条件方式 INSERT

      在语法 ON 关键字处写上恒不等条件(1=2)后,MATCHED 语句的 INSERT

      就变为无条件 INSERT 了。

      MERGE INTO T2

      USING T1 

      ON (1=2)

      WHEN NOT MATCHED THEN 

         INSERT VALUES (T1.NAME,T1.MONEY);

      COMMIT;


3. MERGE 误区探索

3.1 无法在源表中获得一组稳定的行

      在MERGE INTO T2 USING T1 ON … 的 MERGE 表达式中,如果一条T2记录被连接到多条T1记录,

      就产生了ORA-30926错误

      CREATE TABLE T1 (NAME VARCHAR2(20),MONEY NUMBER);

      INSERT INTO T1 VALUES (‘A’,10);

      INSERT INTO T1 VALUES (‘A’,30);

      INSERT INTO T1 VALUES (‘B’,20);

      COMMIT;

      CREATE TABLE T2 (NAME VARCHAR2(20),MONEY NUMBER);

      INSERT INTO T2 VALUES (‘A’,30);     — T2.NAME 连接到多条 T1.NAME

      INSERT INTO T2 VALUES (‘C’,20);

      COMMIT;

      此时继续执行如下语句:

      MERGE INTO T2

      USING T1

      ON (T1.NAME=T2.NAME)

      WHEN MATCHED THEN 

         UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY;

      Oracle 中的 MERGE 语句应该保证 ON 条件的唯一性,T1.NAME=’A’时,T2表记录

      对应到了T1表的两条记录,所以就出错了。

      解决方法:

      a. 对T1表和T2表的关联字段建立主键,这样就基本避免了此类问题,若MERGE语句

          的关联字段互相有主键,MERGE的效率将比较高;

      b. 将T1表的NAME列做一个聚合,这样归并成单条,也能避免此类错误。

      MERGE INTO T2

      USING (SELECT NAME,SUM(MONEY) AS MONEY FROM T1 GROUP BY NAME) T1

      ON (T1.NAME=T2.NAME)

      WHEN MATCHED THEN

         UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY;

      但是这样的改造需要注意,因为有可能改变了最初的需求,此外需要引起注意的是,

      在MERGE INTO T2 USING T1 ON … 的 MERGE 表达式中,如果反过来,一条T1记

      录被连接到多条T2记录,是可以使多条T2记录都被更新而不会出错。

      DROP TABLE T1;

      CREATE TABLE T1 (NAME VARCHAR2(20),MONEY NUMBER);

      INSERT INTO T1 VALUES (‘A’,10);

      INSERT INTO T1 VALUES (‘B’,20);

      DROP TABLE T2;

      CREATE TABLE T2 (NAME VARCHAR2(20),MONEY NUMBER);

      INSERT INTO T2 VALUES (‘A’,30);

      INSERT INTO T2 VALUES (‘A’,40);

      INSERT INTO T2 VALUES (‘C’,20);

      COMMIT;

      此时继续执行如下语句,发现执行可以成功并没有报“无法再源表中获得一组稳定的行”的错误

      MERGE INTO T2 

      USING T1 

      ON (T1.NAME=T2.NAME)

      WHEN MATCHED THEN 

         UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY;  — 此时T2表中NAME=’A’的两条记录都被更新了   

3.2 DELETE 子句的 WHERE 顺序必须在最后

      MERGE INTO T2

      USING T1

      ON (T1.NAME=T2.NAME)

      WHEN MATCHED THEN 

         UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY

   — WHERE T1.NAME=’A’

      DELETE WHERE T2.NAME=’A’; 

3.3 DELETE 子句只可以删除目标表,而无法删除源表

      无论DELETE WHERE T2.NAME=’A’ 这个写法的T2是否改写为T1,效果都一样,都是对目标表进行删除

      MERGE INTO T2 

      USING T1

      ON (T1.NAME=T2.NAME) 

      WHEN MATCHED THEN 

         UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY

      DELETE WHERE T2.NAME=’A’;      —  DELETE WHERE T2.NAME=’A’  删除的还是目标表


























版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/132216.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 海量数据库解决方案 pdf(海量数据处理)

    作者序言这已经是第四次为本书写作者序言了,此时此刻过去20年的生活如同电影般在我的脑海里一一掠过。当我最初决定步入IT领域时就为自己立下了誓言,时至今日回想起多年走过的历程,其间充满了艰辛,也正是这无数的艰辛让我最终体验了收获的愉悦。回望这20多年的足迹,我一直努力用新的视角去观察他人所忽视的领域,尝试用崭新的思维和充满创意的双手去耕耘。尽管如此,也仍然无法紧跟IT技术飞快的发展步伐。我为实现理想而终日不停前行的脚步,虽然忙碌但却无限满足。众所周知,能够加工成宝石的原石比比皆是,一分耕耘,一分收

    2022年4月18日
    32
  • OSTaskCreate创建失败原因之一

    OSTaskCreate创建失败原因之一在μcos中调用这个任务创建函数发现失败,debug进去,发现在err=OS_TCBInit(prio,psp,(OS_STK*)0,0u,0u,(void*)0,0u);后err=OS_ERR_TASK_NO_MORE_TCB这是因为在创建任务之初没有调用OSInit();…

    2022年9月3日
    2
  • 磁盘占用率100%——哪些程序可以禁用(详细版)【还讲到独立显卡、集成显卡、双显卡、固态硬盘卡机卡死卡顿解决】

    磁盘占用率100%——哪些程序可以禁用(详细版)【还讲到独立显卡、集成显卡、双显卡、固态硬盘卡机卡死卡顿解决】我买内存条之前,电脑超级卡的,我不喜欢用完电脑就关机,经常晚上用完就“睡眠、待机”,第二天早上用电脑,一般都打开谷歌浏览器、网易云音乐、有道词典、Eclipse、Oracle、Tomcat、电脑管家、文件资源管理器;我使用Eclipse编写代码,我都输完一行代码,电脑卡的呀,30分钟至一分钟才有反应,这算是快的,最恶心的是“卡至Eclipse软件自己关闭了”!!!所以只能看看哪些服务进程可以禁用…

    2022年6月26日
    24
  • hackbar功能简介

    hackbar功能简介SQL:提供三种数据库的sql查询语句,以及一些方便联合查询的语句XSS:提供xss攻击语句string.fromcharcode():将根据UNICODE值来输出xss语句htmlcharactor:将XSS语句转化为HTML字符实体(以&开头)alert(xss)statement:构建一条xss测…

    2022年5月18日
    72
  • shell脚本给文件重命名_linux移动或重命名文件命令

    shell脚本给文件重命名_linux移动或重命名文件命令文件A重命名为BmvAB;

    2022年9月10日
    0
  • springboot线程池的使用和扩展「建议收藏」

    springboot线程池的使用和扩展「建议收藏」我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行,今天我们就来实战体验这个线程池服务;本文地址:http://blog.csdn.net/boling_cavalry/article/details/79120268实战环境windowns10;jdk1.8;spring

    2022年6月30日
    16

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号