[转载]Oracle Merge的使用

FROM: http://zhangqchang.blog.163.com/blog/static/464989732009219114653226/

摘至网上的几个例子

一、
*****************************************************************
Merger into是oracle从9i开始增加的一个语句,从merge的字面上的意思:合并,

兼并不难理解merge在oracle中的含义,merge在oracle所起的作用是:如果你从

以组值中有选择的更新和插入到到一张表,具体来说是:如果该表中已经匹配了

这组值的某些条件,那么可以使用这组值的部分数据来更新这个表的,如果该表

中无法匹配了这组值的某些条件,那么可以使用这组值的数据来为这个表新增一

条数据。
无论你在使用任何DBMS,你总是难以避免的将会遇到上面提到的这种需求,如果

你不使用merge语句,你将会不得不在程序中增加大段的代码,或者是在oracle用

很长的代码来实现。好在现在我们有了merge,可以帮我们省下很多时间。
好了废话少说:
Merge 的基本语法是这样的
Merge into table[alias]
Using table or sql query [alias]
On condition
When matched then
Update set ….
When not matched then
Insert values…
以上是merge的基本语法,其中alias是为表或者查询写的别名
如果你看着空洞的语法觉得头很痛,看下面的例子吧
首先我们创建两个表
create table test1(id int,name varchar(20));
create table test2(id int,name varchar(20))
然后随意插入几行数据
insert into test1 values(1,’hi’);
insert into test1 values(2,’hello’);
insert into test2 values(2,’你好’);
insert into test2 values(3,’morning’);
下面我们要使用了merge了,将test2中的数据有选择地转移或者更新到test1中
如果你运行了下下面的merge语句,你将会的到一个错误,这是因为oracle规定在

merge语句中不能更新作为连接的列,也就是on后面的那些列
merge into test1 t1
using test2 t2
on (t1.id = t2.id)
when matched then
update set t1.id = t2.id
when not matched then
insert values(t2.id,t2.name);
所以将会得到如下的错误,虽然这个错误翻译的并不怎么样,甚至带有明显的误


on (t1.id = t2.id)
*
ERROR 位于第 3 行:
ORA-00904: “T1″.”ID”: 无效的标识符
好了,知错就改,我们再来运行下面的merge语句。
merge into test1 t1
using test2 t2
on (t1.id = t2.id)
when matched then
update set t1.name = t2.name
when not matched then
insert values(t2.id,t2.name)
成功执行了,我们来验证一下。
select * from test1;

ID NAME
—— —————-
1 hi
2 你好
3 morning
至此,你已经掌握了merge语句中的大部分。但我们还要提醒一些特殊情况。
如果我们再向test2中增加一条语句
insert into test2 values(2,’早’)
再执行我们以已经成功执行过的merge语句,将会遇到下面的错误
SQL> merge into test1 t1
2 using test2 t2
3 on (t1.id = t2.id)
4 when matched then
5 update set t1.name = t2.name
6 when not matched then
7 insert values(t2.id,t2.name)
8 ;
using test2 t2
*
ERROR 位于第 2 行:
ORA-30926: 无法在源表中获得一组稳定的行
这是因为当执行到t1.id = t2.id =2时,test2表中对应了两条记录,无法进行更

新或者插入。所以就出错了。所以你应该明白oracle中的merge语句应该保证on中

的条件的唯一性,
另外一点需要说明的是using关键字后面可以接表,当然也可以接其他的select语

句做出来的一个类视图,oracle中的这种结构,我们在前面已经介绍多次,在此

不作介绍。

二、
*****************************************************************
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=‘100‘,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);

三、
*********************************************************
所有的MIS系统都存在一个同样的需求,就是对于特定的数据,在一次批量操作过

程中,如果数据已经存在,则对存在的数据按照现有情况进行更新,如果不存在

,则需要加入数据库。这时,我们就可以考虑采用 Oracle 的 MERGE 函数,其具

体用法如下:

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 ! ]

下面我再进行详细的说明:

上述代码格式中的加粗字体表示为 Oracle 关键字,[]以及其中的文字均是说

明,在实际使用中不应有 [ words ] 出现。要注意()[圆括号]也是程序的组成

部分。

为了能够使问题与实际问题更加贴切,不妨假设我们现在要给计算机系某个班

的学生批量录入学生成绩。但是,录入时,如果学生的成绩已经存在时,老师只

想对成绩进行修改,而如果成绩不存在则直接添加到库中。我们就老师的这些需

求来构造一个执行语句。

DEFINE TABLE :

SCORE :  using for save the students‘ score informations

STUDENTS : the base information of students

DEFINE COLUMNS :

STUNO : the students‘ ID in the University

STUNAME : students‘ name

COURSENAME : course name

COURSESCORE : the study-results of the reference course

CLASSNAME : where the students study in

STUGRADE : the students grade

TERMNAME : the term which the reference course studied

NOW BEAGIN TO WRITE DOWN THE STATEMENT HERE BLOW THIS LINE !

MERGE INTO SCORE S

USING

(

SELECT A.*,B.*,? MYSCORE FROM SCORE A,STUDENT B

WHERE

A.CLASSNO=? AND A.GRADE=?

AND A.TERMNAME=? AND A.COURSENAME=?

A.STUNO=B.STUNO(+)

)X

ON

(S.STUNO=X.STUNO)

WHEN

MATHED

THEN

UPDATE SET COURSESCORE=X.MYSCORE

WHEN

NOT MATHED

THEN

INSERT

(

STUNO,STUNAME,COURSENAME,COURSESCORE,

CLASSNAME,STUGRADE,TERMNAME

)

VALUES

(

X.STUNO,X.STUNAME,X.COURSENAME,X.MYSCORE,

X.CLASSNAME,X.STUGRADE,X.TERMNAME

);

注意到 MERGE 语句在最后的“;”(分号),这仅仅带到 MERGE 为一条完整的

SQL 语句

这时,如果你需要在你的 Java 程序中使用上述方法执行相应操作,则仅需要

将其放入一个 for 循环中即可。由于是批量更新数据,因此,如果你不想对中间

出现异常的数据进行提交,导致数据的不完整,则可以考虑使用 Java 的事务回

滚机制。具体示例代码如下:

public yourMethod(statement,...){

try{

Connection conn=...;

PreparedStatement ps=...;

Resultset rs=...;

conn.setAutoCommit(false);

for(int i=0;i<...;i++){

//add your code here !

......

ps.addBatch();

}

ps.executeBatch();

conn.commit();

}catch(Exception e){

try{

conn.rollback();

}catch(Exception el){}

}

}

这时,你会发现,在代码中直接使用 Merge 时,代码会变的非常复杂,首先

是 SQL 的拼接变得非常复杂,接下来便是程序写完后的查错。因此,自然而然就

会想到使用存储过程。接下来,我们来看看如何使用存储过程实现 Merge 调用过

程。

Oracle 存储过程定义格式如下:

CREATE OR REPLACE PROCEDURE PRO_YOUR_PROCEDURE (

ELEMENT_01     IN      ELEMENT_TYPE,  --COMMENTS

.......       ....        .....            ....

ELEMENT_0S     OUT     ELEMENT_TYPE,  --COMMENTS

....         ...         ...           ....

)

AS

ARGUMENT_01    ARGUMENT_TYPE(ARGUMENT_RANGE);

...................

BEGIN

MERGE INTO YOUR_TABLE_NAEM [RENAEM_YOUR_TABLE_HERE]

--AND YOUR CODE HERE !

END;

EXCEPTION

WHEN

OTHERS

THEN

RAISE_APPLICATION_ERROR(-20003,[YOUR EXCEPITON MESSAGE HERE !]);

END;

COMMIT;--IF YOUR WANT , JUST DO SO !

END PRO_YOUR_PROCEDURE;

其中,[RAISE_APPLICATION_ERROR(-20003,[YOUR EXCEPITON MESSAGE HERE

!]);]中的“-20003”是 Oracle 提供的用于用户进行错误自定义的扩充代码。其

值可以随便定义,但是也有范围: -20000 到-20999的负整数。

接下来就是如何来在 Java 程序中调用你的存储过程。Oracle为了方便开发人员

调用其存储过程,开发了一个 [ OracleCallableStatement ]  位于

oracle.jdbc 包内。

核心代码如下:

OracleCallableStatement cal = null;

cal=(OracleCallableStatement)conn.getMetaData().getConnection

().prepareCall("call PRO_......");

........

.............

.......

for(………………){

…………

cal.setDouble(i,ARGUMENTS);

…………

  cal.executeUpdate();

}

时间: 2024-10-30 22:27:17

[转载]Oracle Merge的使用的相关文章

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语句

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表更新数

oracle merge用法

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

Oracle merge

oracle merge 語法: 用途: Use the MERGE statement to select rows from one or more sources for update orinsertion into a table or view. You can specify conditions to determine whether toupdate or insert into the target table or view. It lets you avoid mult

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 MERGE INTO的使用方法

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

Oracle MERGE INTO语法探究

1.MERGE INTO 的用途:   MERGE INTO 是Oracle 9i新增的语法,在10g时得到补充,用来合并UPDATE和INSERT语句,根据一张表或子查询与另一张表进行连接查询,连接条件匹配就进行 UPDATE,不匹配就进行INSERT,这个语法仅需要一次全表扫描就可以完成全部工作,执行效率会比单纯的UPDATE+INSERT高,具体应用可用于表之间的同步.2.MERGE INTO 的语法:语法结构:MERGE [INTO [schema .] table [t_alias]

Oracle merge into的优势

简介 Oracle merge into命令,顾名思义就是“有则更新,无则插入”,这个也是merge into 命令的核心思想,在实际开发过程中,我们会经常遇到这种通过两表互相关联匹配更新其中一个表的某些字段的业务,有时还要处理不匹配的情况下的业务.这个时候你会发现随着表的数据量增加,类似这种业务场景的执行效率会比较慢,那是因为你需要多次重复查询两表中的数据,而通过merge into命令,只需要一次关联即可完成“有则更新,无则插入”的业务场景,大大提高语句的执行效率. 语法 1 merge i