MERGE INTO 大量数据插入

1.merge into作用

    在执行大批量的插入更新操作时,按照原有的方式插入或更新效率可能比较低下,而且如果插入多张表的数据时,可能因为违反唯一约束而导致插入失败。

    merge into9i出现的新功能,可以实现在插入数据时,指定某个字段,如果插入的数据已经存在时,进行update的更新或delete删除或不进行操作,然后在插入没有的数据,简单点说就是“有就更新/删除/不操作,无则插入”。

    10g之后,mege into做了写改进,改进如下:

1.updateinsert子句是可选的

2.updateinsert子句可以加where子句

3.on条件中使用常量过滤谓词来insert所有的行到目标表中,不需要连接源表和目标表

4.update子句后面可以跟delete自己来取出一些不需要的行

 

2.merge into 语法

 MERGE [INTO] [schema.]table [alias]

       USING {[schema.]table|views|query} [alias]

       ON {condition}

       WHEN MATCHED THEN UPDATE SET {clause}

       WHEN NOT MATCHED THEN INSERT VALUES {clause}

 

 

3.示列

----环境准备

----创建第一张表

create table shall

 (id number not null,

  name varchar2(20),

  constraint shall_id primary key(id));

 

begin

  for i in 1..10000 loop

   insert into shall values(i,'zhong');

  end loop;

end;

/

 

SQL> select count(*) from shall;

  COUNT(*)

----------

     10000

 

 

----创建第二张表

SQL> create table shall2 as select * from shall where 1=2;

Table created.

 

SQL> select index_name,index_type,tablespace_name,table_type,status from user_indexes where table_name='SHALL2';

no rows selected

----没有唯一索引

SQL> alter table shall2 add constraint shall2_id primary key(id);

Table altered.

 

begin

  for i in 9000..10002 loop

   insert into shall2 values(i,'shall');

  end loop;

end;

/

 

SQL> select count(*) from shall2;

  COUNT(*)

----------

      1003

 

 

----创建第三张表

SQL> create table shall3 as select * from shall where 1=2;

Table created.

 

SQL> alter table shall3 add constraint shall3_id primary key(id);

Table altered.

 

select index_name,index_type,tablespace_name,table_type,status from user_indexes where table_name='SHALL3';

 

----计算数据量(复习集合操作函数)

----shallshall2id都有的数据有多少 1001

SQL> select count(*) from shall t1,shall2 t2 where t1.id=t2.id;

  COUNT(*)

----------

      1001

 

select count(*) from

  (select id from shall

    intersect

   select id from shall2);

 

----shall表中有的id,而shall2中没有的数据量 8999

SQL> select count(*) from shall where id not in (select id from shall2);

  COUNT(*)

----------

      8999

 

select count(*) from

  (select id from shall

    minus

   select id from shall2);

 

----shall2表中有的id,而shall中没有的数据量 2

SQL> select count(*) from shall2 where id not in (select id from shall);

  COUNT(*)

----------

         2

 

select count(*) from

  (select id from shall2

    minus

   select id from shall);

 

----shallshall2id不重复的数据量 10002

SQL> select count(*) from shall t1 full join shall2 t2 on t1.id=t2.id;

  COUNT(*)

----------

     10002

 

select count(*) from

  (select id from shall2

    union

   select id from shall);

 

----shallshall2中共有多少数据 11003

SQL> select (select count(*) from shall) + (select count(*) from shall2) total from dual;

     TOTAL

----------

     11003

 

select count(*) from

  (select id from shall2

    union all

   select id from shall);

 

----下面开始演示merge into

----先将表shall插入到shall3表中。当插入shall3中已经存在的id,不覆盖数据

merge into shall3 t3

  using (select id,name from shall) t

 on (t3.id=t.id)

 when matched then update set t3.name=t.name where 1=2

 when not matched then insert values (t.id,t.name);

 

10000 rows merged.

 

----再将shall2插入到shall3表中。一样,当shall3中已经存在id号的,不覆盖数据

merge into shall3 t3

  using (select id,name from shall2) t

 on (t3.id=t.id)

 when matched then update set t3.name=t.name where 1=2

 when not matched then insert values (t.id,t.name);

 

2 rows merged.

 

----验证一下,是不是第二次插入数据只插入了最后两行

SQL> select * from (select * from shall3 order by id desc) where rownum<5;

        ID NAME

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

     10002 shall

     10001 shall

     10000 zhong

      9999 zhong

 

 

----再次执行merge into插入shall2表数据,要求当shall3表中id存在的时候,更新name字段

merge into shall3 t3

  using (select id,name from shall2) t

 on (t3.id=t.id)

 when matched then update set t3.name=t.name

 when not matched then insert values (t.id,t.name);

 

1003 rows merged.

 

----验证一下,是不是第二次插入数据只插入了最后两行

SQL> select * from (select * from shall3 order by id desc) where rownum<5;

        ID NAME

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

     10002 shall

     10001 shall

     10000 shall

      9999 shall

SQL> select * from shall3 where id between 8999 and 9000;

        ID NAME

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

      8999 zhong

      9000 shall

 

 

----最后试试在on条件中加入 > < 条件看看效果

merge into shall3 t3

  using (select id,name from shall) t

 on (t3.id>t.id)

 when matched then update set t3.name=t.name where 1=2

 when not matched then insert values (t.id,t.name);

 

 

4.merge into 10g新特性演示

----语法如下 

MERGE INTO [your table-name] [rename your table here] 

USING ( [write your query here] )[rename your query-sql and using just like a table] 

ON ([conditional expression here] AND [...]...) 

WHEN MATHED THEN [here you can execute some update sql or something else ] 

WHEN NOT MATHED THEN [execute something else here ! ] 

 

4.1 UPDATE或INSERT子句是可选的 

    9i里由于必须insert intoupdate都要存在,也就是不是update就是insert,不支持单一的操作,虽然还是可以曲线救国,呵呵 但是有些过于强势了。而10g里就是可选了,能符合我们更多的需求了 

比如 

我们可以只存在update或者insert 

merge into products p using newproducts np on (p.product_id = np.product_id) 

when matched then 

update set p.product_name = np.product_name 

这里,如果匹配就更新,不存在就不管了。 

 

4.2 UPDATE和INSERT子句可以加WHERE子句 

    这也是一个功能性的改进,能够符合我们更多的需求,这个where的作用很明显是一个过滤的条件,是我们加入一些额外的条件,对只对满足where条件的进行更新和insert 

merge into products p using (select * from newproducts) np on (p.product_id = np.product_id) 

when matched then 

update set p.product_name = np.product_name where np.product_name like 'OL%' 

这里表示只是对product_name开头是'OL'的匹配上的进行update,如果开头不是'OL'的就是匹配了也不做什么事情,insert里也可以加入where 

比如 

merge into products p using (select * from newproducts) np on (p.product_id = np.product_id) 

when matched then 

update set p.product_name = np.product_name where np.product_name like 'OL%' 

when not matched then 

insert values(np.product_id, np.product_name, np.category) where np.product_name like 'OL%' 

 

这里注意比较一下,他们返回的结果行数,是有着差异的。 

 

4.3 在ON条件中使用常量过滤谓词来insert所有的行到目标表中,不需要连接源表和目标表 

 

merge into products p using (select * from newproducts) np on (1=0) 

when matched then 

update set p.product_name = np.product_name 

when not matched then 

insert values(np.product_id, np.product_name, np.category) 

个人觉得这个功能没有太大的意义,我们的insert into本身就支持这样的功能,没有必要使用merge 

 

4.4 UPDATE子句后面可以跟DELETE子句来去除一些不需要的行 

delete只能和update配合,从而达到删除满足where条件的子句的纪录 

merge into products p using (select * from newproducts) np on (p.product_id = np.product_id) 

when matched then 

update set p.product_name = np.product_name delete where p.product_id = np.product_id where np.product_name like 'OL%' 

when not matched then 

insert values(np.product_id, np.product_name, np.category) 

这里我们达到的目的就是 会把匹配的记录的prodcut_name更新到product里,并且把product_name开头为OL的删除掉。

 

merge into也是一个dml语句,和其他的dml语句一样需要通过rollbackcommit 结束事务。 

 

 

 

 

reference    http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_9016.htm#SQLRF01606

http://blog.youkuaiyun.com/jackpk/article/details/50336941

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30130773/viewspace-2123300/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30130773/viewspace-2123300/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值