oracle merge into用法

Posted 愿将此心传四方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle merge into用法相关的知识,希望对你有一定的参考价值。

在 平时更新数据时,经常有这样一种更新,即将目标表中的数据与源表对比,如果存在记录,则根据源表中的值更新目标表中的数据,如果不存在的话,则新增入目标 表中。我们当然可以使用两条语句来处理这类数据。但这其中有可能会出现异常。因此,Oracle在9i版本新增了MERGE语句,来合并UPDATE和 INSERT语句。 该语句可以在同一语句中执行两步操作,可以减少执行多条insert 和update语句。merge是一个确定性的语句,即不会在同一条merge语句中去对同一条记录多次做修改操作。
     
  具体语法为: 
    MERGE [hint] INTO [schema .] table [t_alias] USING [schema .] 
   { table | view | subquery } [t_alias] ON ( condition ) 
   WHEN MATCHED THEN merge_update_clause 
   WHEN NOT MATCHED THEN merge_insert_clause; 

1.into 子句
在into子句中指定所要修改或者插入数据的目标表

2.using 子句
在using子句中指定用来修改或者插入的数据源。数据源可以是表、视图或者一个子查询语句。

3.on 子句
在on子句中指定执行插入或者修改的满足条件。在目标表中符合条件的每一行,oracle用数据源中的相应数据修改这些行。对于不满足条件的那些行,oracle则插入数据源中相应数据。

4.when matched | not matched
用该子句通知oracle如何对满足或不满足条件的结果做出相应的操作。可以使用以下的两类子句。

5.merge_update子句
merge_update子句执行对目标表中的字段值修改。当在符合on子句条件的情况下执行。如果修改子句执行,则目标表上的修改触发器将被触发。
限制:当修改一个视图时,不能指定一个default值

6.merge_insert 子句
merge_insert子句执行当不符合on子句条件时,往目标表中插入数据。

下面列出merge的基本用法 (此处目标表和源表表结构相同) 
  1) matched 和not matched 同时使用 
   merge into 目标表  a 
     using 源表 b on (关联条件 a.字段1 = b.字段1) 
   when MATCHED then 
        update set a.字段2=b.字段2,...... 
   when NOT MATCHED then 
        insert(a.字段2,a.字段3) 
        values(b.字段2,b.字段3); 
  2) 只有not matched clause,也就是只插入不更新 
   merge into 目标表 a 
     using  源表b on (关联条件 a.字段1 = b.字段1)   
   when NOT MATCHED then 
       insert(a.字段2,a.字段3) 
        values(b.字段2,b.字段3); 

  3) 只有matched clause, 也就是只更新不插入 
   merge into 目标表  a 
     using 源表 b on (关联条件 a.字段1 = b.字段1) 
   when MATCHED then 
        update set a.字段2=b.字段2,...... 
    
另 外,merge命令的update部分可以包含一个delete子句。delete子句(有其自己的where子句)可以删除目标表中被merge更新的 行。delete...where子句可以计算更新值,而不是目标表中的初始值。如果目标表中的行符合delete...where条件但不在merge 所作用(就如on条件所定义的)的行集范围内,就不会删除。 
    具体语法为: 
       using 源表 b on (关联条件 a.字段1 = b.字段1) 
   when MATCHED then 
        update set a.字段2=b.字段2,...... 
        delete where (a.字段5=b.字段5) ; 

   注意:此处的源表可以不仅仅是一张表,也可以是查询出来的结果集。此命令在db2中也同样适用。

首先创建示例表:


create table PRODUCTS
    (
    PRODUCT_ID INTEGER,
    PRODUCT_NAME VARCHAR2(60),
    CATEGORY VARCHAR2(60)
    );

 

    insert into PRODUCTS values (1501, ‘VIVITAR 35MM‘, ‘ELECTRNCS‘);
    insert into PRODUCTS values (1502, ‘OLYMPUS IS50‘, ‘ELECTRNCS‘);
    insert into PRODUCTS values (1600, ‘PLAY GYM‘, ‘TOYS‘);
    insert into PRODUCTS values (1601, ‘LAMAZE‘, ‘TOYS‘);
    insert into PRODUCTS values (1666, ‘HARRY POTTER‘, ‘DVD‘);
    commit;

 

    create table NEWPRODUCTS
    (
    PRODUCT_ID INTEGER,
    PRODUCT_NAME VARCHAR2(60),
    CATEGORY VARCHAR2(60)
    );

 

    insert into NEWPRODUCTS values (1502, ‘OLYMPUS CAMERA‘, ‘ELECTRNCS‘);
    insert into NEWPRODUCTS values (1601, ‘LAMAZE‘, ‘TOYS‘);
    insert into NEWPRODUCTS values (1666, ‘HARRY POTTER‘, ‘TOYS‘);
    insert into NEWPRODUCTS values (1700, ‘WAIT INTERFACE‘, ‘BOOKS‘);
    commit;

 

 

 

1、可省略的UPDATE或INSERT子句

 


在Oracle 9i, MERGE语句要求你必须同时指定INSERT和UPDATE子句.而在Oracle 10g, 你可以省略UPDATE或INSERT子句中的一个. 下面的例子根据表NEWPRODUCTS的PRODUCT_ID字段是否匹配来updates表PRODUCTS的信息:

 

 

 

SQL> MERGE INTO products p
    2 USING newproducts np
    3 ON (p.product_id = np.product_id)
    4 WHEN MATCHED THEN
    5 UPDATE
    6 SET p.product_name = np.product_name,
    7 p.category = np.category;

 

    3 rows merged.

 

    SQL> SELECT * FROM products;

 

    PRODUCT_ID PRODUCT_NAME CATEGORY
    ---------- -------------------- ----------
    1501 VIVITAR 35MM ELECTRNCS
    1502 OLYMPUS CAMERA ELECTRNCS
    1600 PLAY GYM TOYS
    1601 LAMAZE TOYS
    1666 HARRY POTTER TOYS
    SQL>
    SQL> ROLLBACK;
    Rollback complete.
    SQL>

 

 

 


在上面例子中, MERGE语句影响到是产品id为1502, 1601和1666的行. 它们的产品名字和种 类被更新为表newproducts中的值. 下面例子省略UPDATE子句, 把表NEWPRODUCTS中新的PRODUCT_ID插入到表PRODUCTS中, 对于在两个表中能够匹配上PRODUCT_ID的数据不作任何处理. 从这个例子你能看到PRODUCT_ID=1700的行被插入到表PRODUCTS中.

 


SQL> MERGE INTO products p
    2 USING newproducts np
    3 ON (p.product_id = np.product_id)
    4 WHEN NOT MATCHED THEN
    5 INSERT
    6 VALUES (np.product_id, np.product_name,
    7 np.category);

 

    1 row merged.

 

    SQL> SELECT * FROM products;

 

    PRODUCT_ID PRODUCT_NAME CATEGORY
    ---------- -------------------- ----------
    1501 VIVITAR 35MM ELECTRNCS
    1502 OLYMPUS IS50 ELECTRNCS
    1600 PLAY GYM TOYS
    1601 LAMAZE TOYS
    1666 HARRY POTTER DVD
    1700 WAIT INTERFACE BOOKS

 

 

 

2、带条件的Updates和Inserts子句

 


你能够添加WHERE子句到UPDATE或INSERT子句中去, 来跳过update或insert操作对某些行的处理. 下面例子根据表NEWPRODUCTS来更新表PRODUCTS数据, 但必须字段CATEGORY也得同时匹配上:

 


SQL> MERGE INTO products p
    2 USING newproducts np
    3 ON (p.product_id = np.product_id)
    4 WHEN MATCHED THEN
    5 UPDATE
    6 SET p.product_name = np.product_name
    7 WHERE p.category = np.category;

 

    2 rows merged.

 

    SQL> SELECT * FROM products;

 

    PRODUCT_ID PRODUCT_NAME CATEGORY
    ---------- -------------------- ----------
    1501 VIVITAR 35MM ELECTRNCS
    1502 OLYMPUS CAMERA ELECTRNCS
    1600 PLAY GYM TOYS
    1601 LAMAZE TOYS
    1666 HARRY POTTER DVD
    SQL>
    SQL> rollback;

 

 

 


在这个例子中, 产品ID为1502,1601和1666匹配ON条件但是1666的category不匹配. 因此MERGE命令只更新两行数据. 下面例子展示了在Updates和Inserts子句都使用WHERE子句:

 


SQL> MERGE INTO products p
    2 USING newproducts np
    3 ON (p.product_id = np.product_id)
    4 WHEN MATCHED THEN
    5 UPDATE
    6 SET p.product_name = np.product_name,
    7 p.category = np.category
    8 WHERE p.category = ‘DVD‘
    9 WHEN NOT MATCHED THEN
    10 INSERT
    11 VALUES (np.product_id, np.product_name, np.category)
    12 WHERE np.category != ‘BOOKS‘
    SQL> /

 

    1 row merged.

 

    SQL> SELECT * FROM products;

 

    PRODUCT_ID PRODUCT_NAME CATEGORY
    ---------- -------------------- ----------
    1501 VIVITAR 35MM ELECTRNCS
    1502 OLYMPUS IS50 ELECTRNCS
    1600 PLAY GYM TOYS
    1601 LAMAZE TOYS
    1666 HARRY POTTER TOYS

 

    SQL>

 

 

 

注意由于有WHERE子句INSERT没有插入所有不匹配ON条件的行到表PRODUCTS.

 

 

 

3、无条件的Inserts

 


你能够不用连接源表和目标表就把源表的数据插入到目标表中. 这对于你想插入所有行到目标表时是非常有用的. Oracle 10g现在支持在ON条件中使用常量过滤谓词. 举个常量过滤谓词例子ON (1=0). 下面例子从源表插入行到表PRODUCTS, 不检查这些行是否在表PRODUCTS中存在:

 

SQL> MERGE INTO products p
    2 USING newproducts np
    3 ON (1=0)
    4 WHEN NOT MATCHED THEN
    5 INSERT
    6 VALUES (np.product_id, np.product_name, np.category)
    7 WHERE np.category = ‘BOOKS‘
    SQL> /

 

    1 row merged.

 

    SQL> SELECT * FROM products;

 

    PRODUCT_ID PRODUCT_NAME CATEGORY
    ---------- -------------------- ----------
    1501 VIVITAR 35MM ELECTRNCS
    1502 OLYMPUS IS50 ELECTRNCS
    1600 PLAY GYM TOYS
    1601 LAMAZE TOYS
    1666 HARRY POTTER DVD
    1700 WAIT INTERFACE BOOKS
    6 rows selected.
    SQL>

 

 

 


 

 

4、新增加的DELETE子句

 


Oracle 10g中的MERGE提供了在执行数据操作时清除行的选项. 你能够在WHEN MATCHED THEN UPDATE子句中包含DELETE子句. DELETE子句必须有一个WHERE条件来删除匹配某些条件的行.匹配DELETE WHERE条件但不匹配ON条件的行不会被从表中删除.

 


下面例子验证DELETE子句. 我们从表NEWPRODUCTS中合并行到表PRODUCTS中, 但删除category为ELECTRNCS的行.

 


SQL> MERGE INTO products p
    2 USING newproducts np
    3 ON (p.product_id = np.product_id)
    4 WHEN MATCHED THEN
    5 UPDATE
    6 SET p.product_name = np.product_name,
    7 p.category = np.category
    8 DELETE WHERE (p.category = ‘ELECTRNCS‘)
    9 WHEN NOT MATCHED THEN
    10 INSERT
    11 VALUES (np.product_id, np.product_name, np.category)
    SQL> /

 

    4 rows merged.

 

    SQL> SELECT * FROM products;

 

    PRODUCT_ID PRODUCT_NAME CATEGORY
    ---------- -------------------- ----------
    1501 VIVITAR 35MM ELECTRNCS
    1600 PLAY GYM TOYS
    1601 LAMAZE TOYS
    1666 HARRY POTTER TOYS
    1700 WAIT INTERFACE BOOKS
    SQL>

 


产品ID为1502的行从表PRODUCTS中被删除, 因为它同时匹配ON条件和DELETE WHERE条件. 产品ID为1501的行匹配DELETE WHERE条件但不匹配ON条件, 所以它没有被删除. 产品ID为1700 的行不匹配ON条件, 所以被插入表PRODUCTS. 产品ID为1601和1666的行匹配ON条件但不匹配DELETE WHERE条件, 所以被更新为表NEWPRODUCTS中的值.

 

**************************************************************************************************

 

定义游标类型

 

CREATE OR REPLACE PACKAGE 包名 IS

 

   创建作者:

 

   创建日期:

 

   功能描述:定义ref cursor变量类型
   实现逻辑:
  TYPE TYPE_CURSOR IS REF CURSOR;   --定义游标变量

 

包体:

 

CREATE OR REPLACE PACKAGE 包名 IS

 

procedure 存过名(

 

.........

 

) as

 

CURSOR_MODULEID TYPE_CURSOR; --模块游标

 

begin

 

OPEN CURSOR_MODULEID FOR
      SELECT DISTINCT (MODULEID)
      FROM SYS_USERROLE A, SYS_ROLEPERMIT B
      WHERE USERID = I_USER
      AND A.ROLEID = B.ROLEID;

 

......

 

end;

 

 

CURSOR cur_prod is
           select branch,remainprinamt
           from prod_daily_prin_branch
           where prodid=is_prodid
                 and cdate = is_cdate;

 

begin

 

open cur_prod;
    loop
        fetch cur_prod into vs_brach,vn_prinamt;
        exit when cur_prod%notfound;
        --销售费
        vn_sale := vn_prinamt*vn_syield/vn_basis;
        merge into bm_yieldassign a
        using
        (select is_cdate as cdate
                ,vs_assetpool as assetpool
                ,vs_brach as branch
                ,0 as assetofamt       --资产提供额
                ,0 as hostamt          --托管费
                ,0 as assetamt         --资产推介费
                ,decode(vs_mktdeptno,‘L‘,vn_prinamt,0) as reprinamt --零售销售额
                ,decode(vs_mktdeptno,‘L‘,vn_sale,0) as resamt       --零售销售费
                ,decode(vs_mktdeptno,‘T‘,vn_prinamt,0) as typrinamt --同业销售额
                ,decode(vs_mktdeptno,‘T‘,vn_sale,0) as tysamt       --同业销售费
                ,decode(vs_mktdeptno,‘G‘,vn_prinamt,0) as cwprinamt --公司销售额
                ,decode(vs_mktdeptno,‘G‘,vn_sale,0) as cwsamt       --公司销售费
         from dual) b
         on (a.cdate = b.cdate
              and a.assetpool=b.assetpool
              and a.branch = b.branch)
         when matched then
              update  set a.reprinamt = nvl(a.reprinamt,0)+b.reprinamt,
                          a.resamt = nvl(a.resamt,0) + b.resamt,
                          a.typrinamt = nvl(a.typrinamt,0) + b.typrinamt,
                          a.tysamt = nvl(a.tysamt,0) + b.typrinamt,
                          a.cwprinamt = nvl(a.cwprinamt,0) + b.cwprinamt,
                          a.cwsamt = nvl(a.cwsamt,0) + b.cwsamt
         when not matched then
              insert(cdate,assetpool,branch
                      ,assetofamt,hostamt,assetamt
                      ,reprinamt,resamt
                      ,typrinamt,tysamt
                      ,cwprinamt,cwsamt
                      ,lstmntuser,lstmntdate)
                  values(b.cdate,b.assetpool,b.branch
                      ,b.assetofamt,b.hostamt,b.assetamt
                      ,b.reprinamt,b.resamt
                      ,b.typrinamt,b.tysamt
                      ,b.cwprinamt,b.cwsamt
                      ,is_operator,sysdate);
    end loop;
    close cur_prod;

 

以上是关于oracle merge into用法的主要内容,如果未能解决你的问题,请参考以下文章

oracle merge into 用法详解

oracle中的merge into用法解析

oracle merge into用法

Oracle中Merge into用法总结

oracle中 merge into 的用法

Oracle中Merge into用法总结