zoukankan      html  css  js  c++  java
  • Merge Into 语句代替Insert/Update在Oracle中的应用实战

    动机:

    想在Oracle中用一条SQL语句直接进行Insert/Update的操作。

    说明:

    在进行SQL语句编写时,我们经常会遇到大量的同时进行Insert/Update的语句 ,也就是说当存在记录时,就更新(Update),不存在数据时,就插入(Insert)。

    实战:

    接下来我们有一个任务,有一个表T,有两个字段a,b,我们想在表T中做Insert/Update,如果存在,则更新T中b的值,如果不存在,则插入一条记录。在Microsoft的SQL语法中,很简单的一句判断就可以了,SQL Server中的语法如下:

    if exists(select 1 from T where T.a='1001' ) update T set T.b=2 Where T.a='1001' else insert into T(a,b) values('1001',2);

    以上语句表明当T表中如果存在a='1001' 的记录的话,就把b的值设为2,否则就Insert一条a='1001',b=2的记录到T中。

    但是接下来在Oracle中就遇到麻烦了,记得在Oracle 9i之后就有一条Merge into 的语句可以同时进行Insert 和Update的吗,Merge的语法如下:

    MERGE INTO table_name alias1 
    USING (table|view|sub_query) alias2
    ON (join condition) 
    WHEN MATCHED THEN 
        UPDATE table_name 
        SET col1 = col_val1, 
            col2     = col2_val 
    WHEN NOT MATCHED THEN 
        INSERT (column_list) VALUES (column_values); 

    上面的语法大家应该都容易懂吧,那我们按照以上的逻辑再写一次。

    MERGE INTO T T1
    USING (SELECT a,b FROM T WHERE t.a='1001') T2
    ON ( T1.a=T2.a)
    WHEN MATCHED THEN
      UPDATE SET T1.b = 2
    WHEN NOT MATCHED THEN 
      INSERT (a,b) VALUES('1001',2);

    以上的语句貌似很对是吧,实际上,该语句只能进行更新,而无法进行Insert,错误在哪里呢?

    其实在Oracle中Merge语句原先是用来进行整表的更新用的,也就是ETL工具比较常用的语法,重点是在Using上。

    用中文来解释Merge语法,就是:

    在alias2中Select出来的数据,每一条都跟alias1进行 ON (join condition)的比较,如果匹配,就进行更新的操作(Update),如果不匹配,就进行插入操作(Insert)。

    因此,严格意义上讲,”在一个同时存在Insert和Update语法的Merge语句中,总共Insert/Update的记录数,就是Using语句中alias2的记录数。”

    以上这句话也就很好的解释了在上面写的语句为何只能进行Update,而不能进行Insert了,因为都Select不到数据,如何能进行Insert呢:)

    接下来要改成正确的语句就容易多了,如下:

    MERGE INTO T T1
    USING (SELECT '1001' AS a,2 AS b FROM dual) T2
    ON ( T1.a=T2.a)
    WHEN MATCHED THEN
      UPDATE SET T1.b = T2.b
    WHEN NOT MATCHED THEN 
      INSERT (a,b) VALUES(T2.a,T2.b);

    查询结果,OK!

    注意:

    如果不懂Merge语句的原理,Merge语句是一条比较危险的语句,特别是在您只想更新一条记录的时候,因为不经意间,你可能就把整表的数据都Update了一遍.....汗!!!

    我曾经犯过的一个错误如下所示,大家看出来是什么问题了吗?

    MERGE INTO T T1
    USING (SELECT Count(*) cnt FROM T WHERE T.a='1001') T2
    ON (T2.cnt>0)
    WHEN MATCHED THEN
      UPDATE SET T1.b = T2.b
    WHEN NOT MATCHED THEN 
      INSERT (a,b) VALUES(T2.a,T2.b);

     

  • 相关阅读:
    HDU4366 Successor 线段树+预处理
    POJ2823 Sliding Window 单调队列
    HDU寻找最大值 递推求连续区间
    UVA846 Steps 二分查找
    HDU3415 Max Sum of MaxKsubsequence 单调队列
    HDU时间挑战 树状数组
    UVA10168 Summation of Four Primes 哥德巴赫猜想
    UESTC我要长高 DP优化
    HDUChess 递推
    HDU4362 Dragon Ball DP+优化
  • 原文地址:https://www.cnblogs.com/baizhanshi/p/8405136.html
Copyright © 2011-2022 走看看