[转载]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();
}
[转载]Oracle Merge的使用的更多相关文章
- Oracle Merge into 详细介绍
Oracle Merge into 详细介绍 /*Merge into 详细介绍MERGE语句是Oracle9i新增的语法,用来合并UPDATE和INSERT语句.通过MERGE语句,根据一张表或子查 ...
- Oracle merge
oracle merge 語法:
- Oracle merge合并更新函数
本博客介绍一下Oracle merge合并函数,业务场景:新增数据的时候要先查询数据库是否已经有改数据,有数据就更新数据,没数据才新增数据,这是很常见的业务场景,如果是用Oracle数据库的话,其实直 ...
- ORACLE MERGE INTO UPDATE DELETE 用法
ORACLE MERGE INTO UPDATE DELETE 用法 使用该MERGE语句从一个或多个源中选择行以进行更新或插入表或视图.您可以指定条件以确定是更新还是插入目标表或视图. 此语句是组合 ...
- oracle merge into与sqlserver merge into 比较
merge into: 在两个表之间,根据与源表联接的结果,对目标表执行插入.更新或删除操作. Oracle在9i引入了merge into命令,SQL Server 2008也引入merge int ...
- Oracle merge into的优势
简介 Oracle merge into命令,顾名思义就是“有则更新,无则插入”,这个也是merge into 命令的核心思想,在实际开发过程中,我们会经常遇到这种通过两表互相关联匹配更新其中一个表的 ...
- Oracle—merge into语法
oracle的merge into语法,在这种情况下: 基于某些字段,存在就更新,不存在就插入: 不需要先去判断一下记录是否存在,直接使用merge into merge into 语法: MERGE ...
- oracle merge into用法
转载:http://blog.163.com/duanpeng3@126/blog/static/885437352011724104741817/ 在 平时更新数据时,经常有这样一种更新,即将目标表 ...
- Oracle merge into
Oracle中Merge into用法总结 文件来源:(http://blog.csdn.net/yuzhic/article/details/1896878) 有一个表T,有两个字段a.b,我们想在 ...
随机推荐
- POJ1258 (最小生成树prim)
Agri-Net Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 46319 Accepted: 19052 Descri ...
- linux下rm命令删除文件名中包含特殊字符的文件【转】
转自:http://blog.itpub.net/143526/viewspace-1060083/ 1. 删除带“-”的文件名的方法 2. 删除包含其它特殊字符的文件 3. 删除系统打不出的乱码文件 ...
- BigDecimal常用操作
import java.math.BigDecimal; public class BigDecimalUtil { /** * 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精 ...
- 使用bottle进行web开发(5):Generating Content
在纯粹的 WSGI中,你的应用能返回的数据类型是十分有限的,你必须返回可迭代的字符串,你能返回字符串是因为字符串是可以迭代的,但是这导致服务器将你的内容按一字符一字符的传送,这个时候,Unicode ...
- vs code 体验
今天用了一下 vs code, 第一感觉非常棒.用过 sublime text 和 vs 的经验.对vs code有一种曾相识的感觉. 在界面体验上,比目前用的 sublime text的感觉要好,比 ...
- java类型强转
知乎: 首先基本数据类型不是对象,强转改的是值,分为有损和无损,有损会丢失数据细节. 然后对象,只有继承关系的类才能强转,改变的只是引用,而且向上转型是安全的,把你转为人类是安全的,你还是你,只是现在 ...
- Linux下安装Sybase ASE 16
https://jingyan.baidu.com/article/414eccf67281a16b421f0a76.html
- 【互动问答分享】第5期决胜云计算大数据时代Spark亚太研究院公益大讲堂
Spark亚太研究院100期公益大讲堂 [第5期互动问答分享] Q1:spark怎样支持即席,应该不是spark sql吧,是hive on spark么? Spark1.0 以前支持即席查询的技术是 ...
- ubuntu下执行ulimit返回“不允许的操作”,问题解决思路
在ubuntu下执行ulimit,希望修改允许的最大打开文件数,但返回“不允许的操作”. 使用ulimit -a查看当前配置 core file size (blocks, -c) 0 data se ...
- 【转】jmeter入门教程- Jmeter教程及技巧汇总
https://blog.csdn.net/zouxiongqqq/article/details/72843500