[Oracle] 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;

MERGE是什么,如何使用呢?让我们先看一个简单的需求:

需求是,从T1表更新数据到T2表中,如果T2表的NAME 在T1表中已存在,就将MONEY累加,如果不存在,将T1表的记录插入到T2表中。

大家知道,在等价的情况下,一定需要至少两条语句,一条为UPDATE,一条为INSERT,而且语句中必须要与判断的逻辑,或者写在过程中,如果是单条语句,就要写全条件,

写在UPDATE和INSERT的语句中,显的比较麻烦而且容易出错。如果了解MERGE,我们可以不借助存储过程,直接用单条SQL便实现了该业务逻辑,且代码很简洁,具体如下:

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);

Merge的四大灵活之处

上面讲了Merge的语法和基本用法,事实上Merge可以非常灵活。

1.UPDATE和INSERT动作可只出现其一(9I必须同时出现!)

--我们可选择仅仅UPDATE目标表
MERGE INTO T2
USING T1
ON (T1.NAME=T2.NAME)
WHEN MATCHED THEN
UPDATE
SET T2.MONEY=T1.MONEY+T2.MONEY;

--也可选择仅仅INSERT目标表而不做任何UPDATE动作

MERGE INTO T2
USING T1
ON (T1.NAME=T2.NAME)
WHEN NOT MATCHED THEN
INSERT
VALUES (T1.NAME,T1.MONEY);

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';

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');

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);

Merge的误区

1. 不能更新ON子句引用的列

MERGE INTO T2
USING T1
ON (T1.NAME=T2.NAME)
WHEN MATCHED THEN
UPDATE
SET T2.NAME=T1.NAME;

ORA-38104: 无法更新 ON 子句中引用的列: "T2"."NAME"

2. DELETE子句的WHERE顺序必须最后

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')
WHERE T1.NAME='A';

ORA-00933: SQL 命令未正确结束

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

/*
 这里需要引起注意,无论DELETE WHERE (T2.NAME = 'A' )这个写法的T2是否改写为T1,效果都一样,都是对目标表进行删除!
*/

SELECT * FROM T1;
NAME                      MONEY
-------------------- ----------
A                            10
B                            20

SELECT * FROM T2;
NAME                      MONEY
-------------------- ----------
A                            30
C                            20

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' );

SELECT * FROM T1;

NAME                      MONEY
-------------------- ----------
A                            10
B                            20

SELECT * FROM T2;

NAME                      MONEY
-------------------- ----------
C                            20

4.更新同一张表的数据,需担心USING的空值

SELECT * FROM T2;
NAME                      MONEY
-------------------- ----------
A                            30
C                            20

/*

需求为对T2表进行自我更新,如果在T2表中发现NAME=D的记录,就将该记录的MONEY字段更新为100,如果NAME=D的记录不存在,
则自动增加,NAME=D并且MONEY=100的记录。根据语法完成如下代码:

*/

MERGE INTO T2
USING (select * from t2 where NAME='D') T
ON (T.NAME=T2.NAME)
WHEN MATCHED THEN
UPDATE
SET T2.MONEY=100
WHEN NOT MATCHED THEN
INSERT
VALUES ('D',200);

--但是查询发现,本来T表应该因为NAME=D不存在而要增加记录,但是实际却根本无变化。
SQL> SELECT * FROM T2;
NAME                      MONEY
-------------------------------------------------------
A                            30
C                            20

/*
   原来是因为此时select * from t2 where NAME='D'为NULL,所以出现了无法插入的情况,
   我们可以利用COUNT(*)的值不会为空的特点来等价改造,具体如下:
*/

MERGE INTO T2
USING (select COUNT(*) CNT from t2 where NAME='D') T
ON (T.CNT<>0)
WHEN MATCHED THEN
UPDATE
SET T2.MONEY=100
WHEN NOT MATCHED THEN
INSERT
VALUES ('D',100);

SQL> SELECT * FROM T2;
NAME                      MONEY
-------------------------------
A                            30
C                            20
D                           100

5. 必须要在源表中获得一组稳定的行

---构造数据,请注意这里多插入一条A记录,就产生了ORA-30926错误
INSERT INTO T1 VALUES ('A',30);
COMMIT;

---此时继续执行如下
MERGE INTO T2
USING T1
ON (T1.NAME=T2.NAME)
WHEN MATCHED THEN
UPDATE
SET T2.MONEY=T1.MONEY+T2.MONEY;
ORA-30926: 无法在源表中获得一组稳定的行

/*
oracle中的merge语句应该保证on中的条件的唯一性,T1.NAME=T2.NAME的时候,T1表记录对应到了T2表的两条记录,所以就出错了。
解决方法很简单,比如我们可以对T1表和T2表的关联字段建主还键,这样基本上就不可能出现这样的问题,而且一般而言,MERGE语句的关联字段互相有主键,
MERGE的效率将比较高!或者是将T1表的ID列做一个聚合,这样归并成单条,也能避免此类错误。如:
*/   

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;

--正常情况下,一般出现重复的NAME需要引起怀疑,不太应该。 

[Oracle] Merge语句,布布扣,bubuko.com

时间: 2024-10-16 12:03:48

[Oracle] Merge语句的相关文章

ORACLE MERGE INTO语句,unable to get a stable set of rows in the source tables报错解决

ORACLE数据库,MERGE INTO语句,经常会出现  ORA-30926: unable to get a stable set of rows in the source tables   这个错误,如下图所示: 经检查,这个错误是由于数据来源表(即语句中,from关键字后面的表)存在数据重复造成的.在实际项目研发中,我们一般不能随便改动数据表的记录,那么如何避免这种错误的产生以及如何改正错误呢? 请看下面的SQL: MERGE INTO TEMP_ZL_ACCOUNTLIST t1 U

oracle SQL语句练习MERGE、模糊查询、排序、

Oracle支持的SQL指令可分为数据操作语言语句.数据定义语言语句.事务控制语句.会话控制语句等几种类型:1.数据操作语言语句数据操作语言语句(Data manipulation language,DML)用于进行数据的检索和更新操作.数据检索是数据库应用中使用频率最高的操作类型,因此数据检索的效率对数据库的整体性能影响显著.数据更新包括数据的插入.修改和删除等操作,数据更新操作具有一定的风险性,在其执行过程中DBMS必须保证数据的一致性,以确保数据有效.SELECT.INSERT.DELET

Oracle 中MERGE语句的用法(转载)

原文章出处(http://blog.csdn.net/lichkui/article/details/4306299) MERGE语句是Oracle9i新增的语法,用来合并UPDATE和INSERT语句.通过MERGE语句,根据一张表或子查询的连接条件对另外一张表进行查询,连接条件匹配上的进行UPDATE,无法匹配的执行INSERT.这个语法仅需要一次全表扫描就完成了全部工作,执行效率要高于INSERT+UPDATE. //表1create table subs(msid number(9), 

Oracle Merge into [转] [ http://www.cnblogs.com/dongsheng/p/4384754.html]

Oracle中Merge into用法总结 起因: 前段时间,因为涉及到一张表的大数据操作,要同时进行增删改,我跟师傅想了很多优化办法,结果都不尽人意.刚开始用的就是原始算法,先更新现有记录,再插入满足要求的其他记录,最后再删除多余记录,但是少量数据还可以,10W条数据就不行了,前台的超时时间是60s,远远无法满足要求.之后又想办法将任务进行拆分,根据每条记录流水号尾字符不同进行拆分,用多个线程同时执行,一直拆分成10个任务(尾字符分别为0.1.2.3 ... 9),用十个线程同时去执行,但是时

Oracle MERGE INTO的用法

很多时候我们会出现如下情境,如果一条数据在表中已经存在,对其做update,如果不存在,将新的数据插入.如果不使用Oracle提供的merge语法的话,可能先要上数据库select查询一下看是否存在,然后决定怎么操作,这样的话需要写更多的代码,同时性能也不好,要来回数据库两次.使用merge的话则可以一条SQL语句完成. 1)主要功能 提供有条件地更新和插入数据到数据库表中 如果该行存在,执行一个UPDATE操作,如果是一个新行,执行INSERT操作 - 避免了分开更新 - 提高性能并易于使用

oracle merge into 的例子

内容来自 oracle 11g 实用教程 郑阿奇等编 在 oracle 11g中有merge语句,用于根据与原表连接的结果,对目标表执行插入,更新,或者删除操作.例如,根据在一个表中找到的差异在另一个表中插入,更新或者删除行,这种方法可以对两个表进行信息同步.语法格式如下 merge into <目标表名> using <原表名>on <条件表达式> when matched then {update set ...|delete} when not matched t

oracle merge用法

动机: 想在Oracle中用一条SQL语句直接进行Insert/Update的操作. 说明: 在进行SQL语句编写时,我们经常会遇到大量的同时进行Insert/Update的语句 ,也就是说当存在记录时,就更新(Update),不存在数据时,就插入(Insert). 实战: 接下来我们有一个任务,有一个表T,有两个字段a,b,我们想在表T中做Insert/Update,如果存在,则更新T中b的值,如果不存在,则插入一条记录.在Microsoft的SQL语法中,很简单的一句判断就可以了,SQL S

数据库基本概念及Oracle基本语句

一.数据库分类 通常是按照数据模型的特点将传统数据库系统分成网状数据库.层次数据库和关系数据库三种. 1.网状数据库 顾名思义,网状数据库采用的是以记录类型为结点的网状数据模型,是一种导航式(Navigation)的数据库--用户在操作数据库时不但要指明要访问的对象(数据),还要规定其存取路径. 网状数据库模型对于层次和非层次结构的信息都能比较自然的模拟,在关系数据库出现之前网状DBMS要比层次DBMS用得普遍.在数据库发展史上,网状数据库占有重要地位. 2.层次型数据库 紧随网络型数据库之后出

oracle merge into用法

Oracle 10g中MERGE有如下一些改进: 1.UPDATE或INSERT子句是可选的 2.UPDATE和INSERT子句可以加WHERE子句 3.ON条件中使用常量过滤谓词来insert所有的行到目标表中,不需要连接源表和目标表 4.UPDATE子句后面可以跟DELETE子句来去除一些不需要的行 Oracle9i引入了MERGE命令,你能够在一个SQL语句中对一个表同时执行inserts和updates操作. MERGE命令从一个或多个数据源中选择行来updating或inserting