Oracle的Merge into用法总结

本文详细介绍了SQL中的Merge Into语句用法,包括如何在Oracle中实现条件更新或插入操作,以及如何使用OUTPUT子句输出变动数据。此外还介绍了如何通过附加条件限制更新范围。

简单的说就是,判断表中有没有符合on()条件中的数据,有了就更新数据,没有就插入数据。  

有一个表T,有两个字段a、b,我们想在表T中做Insert/Update,如果条件满足,则更新T中b的值,否则在T中插入一条记录。在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);

但是很明显这个语法对于SQL只能更改一条语句,并且Oracle不能使用.所以就有了Merge into(Oracle 9i引入的功能)语法 :

merge into 目标表 a
 
using 源表 b
 
on(a.条件字段1=b.条件字段1 and a.条件字段2=b.条件字段2 ……)  
 
when matched then update set a.更新字段=b.字段
 
when  not macthed then insert into a(字段1,字段2……)values(值1,值2……)

"在一个同时存在Insert和Update语法的Merge语句中,总共Insert/Update的记录数,就是Using语句中"源表"的记录数"

 源表b可能是一张表结构不同于a的表,有可能是一张构建相同表结构的临时表,也有可能是我们自己组起来的数据.

对于前两种很好理解。现在主要说一下组件数据。

对于Oracle有dual这个系统表很好构建,如下:

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

Merge 的其他功能

 Merge语句还有一个强大的功能是通过OUTPUT子句,可以将刚刚做过变动的数据进行输出。我们在上面的Merge语句后加入OUTPUT子句:

SELECT * FROM TargetTable 
SELECT * FROM SourceTable
MERGE INTO TargetTable AS T
USING SourceTable AS S
ON T.id = S.id
WHEN MATCHED  ---当上面的on后面的T.id=S.id时,目标表中的id为1,2的数据被更新
THEN NOT MATCHED  --目标表中没有的ID,在原来表有,则插入相关数据
THEN INSERT VALUES(S.id,S.[DESC])
WHEN NOT MATCHED BY SOURCE --目标表中存在,原表中不存在则删除
THEN DELETE
OUTPUT $ACTION AS [ACTION],Inserted.id as 插入的id,
    Inserted.[DESC] as 插入的DESC,
    deleted.id as 删除的id,
    deleted.[DESC] as 删除的DESC;

   此时Merge操作完成后,将所变动的语句进行输出:

   当然了,上面的Merge关键字后面使用了多个WHEN…THEN语句,而这个语句是可选的.也可以仅仅新增或是仅仅删除:

MERGE INTO TargetTable AS T
USING SourceTable AS S
ON T.id = S.id
THEN NOT MATCHED  --目标表中没有的ID,在原来表有,则插入相关数据
THEN INSERT VALUES(S.id,S.[DESC])
OUTPUT $ACTION AS [ACTION],Inserted.id as 插入的id,
    Inserted.[DESC] as 插入的DESC,
    deleted.id as 删除的id,
    deleted.[DESC] as 删除的DESC;

   我们还可以使用TOP关键字限制目标表被操作的行,如图8所示。在图2的语句基础上加上了TOP关键字,我们看到只有两行被更新:

MERGE TOP(2) TargetTable AS T
USING SourceTable AS S
ON T.id = S.id
WHEN MATCHED  ---当上面的on后面的T.id=S.id时,目标表中的id为1,2的数据被更新
THEN NOT MATCHED  --目标表中没有的ID,在原来表有,则插入相关数据
THEN INSERT VALUES(S.id,S.[DESC])
WHEN NOT MATCHED BY SOURCE --目标表中存在,原表中不存在则删除
THEN DELETE
OUTPUT $ACTION AS [ACTION],Inserted.id as 插入的id,
    Inserted.[DESC] as 插入的DESC,
    deleted.id as 删除的id,
    deleted.[DESC] as 删除的DESC;

    但仅仅是MATCHED这种限制条件往往不能满足实际需求,我们可以在图7那个语句的基础上加上AND附加上额外的限制条件:

MERGE INTO TargetTable AS T
USING SourceTable AS S
ON T.id = S.id
THEN NOT MATCHED AND S.id = 3 --加入了id=3的限制条件
THEN INSERT VALUES(S.id,S.[DESC])
OUTPUT $ACTION AS [ACTION],Inserted.id as 插入的id,
    Inserted.[DESC] as 插入的DESC,
    deleted.id as 删除的id,
    deleted.[DESC] as 删除的DESC;

转自https://blog.youkuaiyun.com/spw55381155/article/details/79891305

相关文章参考:https://blog.youkuaiyun.com/jeryjeryjery/article/details/70047022

<think>嗯,用户正在询问Oracle数据库中MERGE INTO语句的使用方法。我需要基于提供的引用内容来整理一个清晰的回答。 引用[1]提到MERGE INTO结合了INSERT、UPDATE和DELETE操作,被称为"upsert"[^1]。引用[4]给出了基本语法结构:使用USING指定源表,ON定义匹配条件,然后分别处理MATCHED和NOT MATCHED的情况[^4]。引用[5]特别指出这个语句适用于表关系一对一的情况,一对多时会报错[^5]。 用户可能需要具体示例理解用法。引用[4]的示例很典型:当员工号匹配时更新工资,特定条件下删除记录,不匹配时插入新数据[^4]。引用[5]的案例展示了字段同步场景,用MATERIAL_CODE作为关联键,匹配时更新名称,不匹配时插入新记录[^5]。 还要提醒注意事项。引用[3]提到该语句在复杂场景(如视图更新、分区表)可能存在BUG[^3],引用[2]则说明它常用于数据同步、整合等场景[^2]。这些补充信息能让用户更全面评估使用风险。 最后考虑设计相关问题:语法细节、一对一限制的具体表现、典型应用案例、与普通DML的对比、以及那个有趣的"源数据空集仍能匹配"的BUG[^3]。这些问题能帮助用户深化理解。 </think>以下是Oracle数据库`MERGE INTO`语句的详细使用方法,结合核心功能、语法结构、注意事项和应用场景: ### 一、核心功能 1. **数据合并(Upsert)** 根据匹配条件,自动执行`UPDATE`(存在匹配记录)或`INSERT`(无匹配记录),减少代码量[^1][^2]。 2. **可选DELETE子句** 在`UPDATE`后可追加`DELETE WHERE`,仅在更新后满足条件时删除目标表记录[^4]。 ### 二、基础语法 ```sql MERGE INTO 目标表 a -- 需操作的表(可用别名) USING 源数据集 b -- 可以是表/视图/子查询 ON (a.关联键 = b.关联键) -- 匹配条件 WHEN MATCHED THEN -- 匹配时执行UPDATE/DELETE UPDATE SET a.字段 = b.字段 [DELETE WHERE 条件] -- 可选删除 WHEN NOT MATCHED THEN -- 不匹配时执行INSERT INSERT (a.列1, a.列2...) VALUES (b.列1, b.列2...); ``` ### 三、使用示例 #### 场景1:同步两表数据(一对一关系) ```sql MERGE INTO PMP_ENQUIRY_PRICE A -- 目标表 USING PMP_MATERIAL_DETAILED B -- 源表 ON (A.MATERIAL_CODE = B.DESC12) -- 关联键 WHEN MATCHED THEN UPDATE SET A.MATERIAL_NAME = B.DESC1 -- 更新名称 WHEN NOT MATCHED THEN INSERT (A.ID, A.MATERIAL_CODE, A.MATERIAL_NAME) VALUES (SYS_GUID(), B.DESC12, B.DESC1); -- 插入新记录[^5] ``` #### 场景2:更新特定记录并删除 ```sql MERGE INTO test_emp a USING emp b ON (a.EMPNO = b.EMPNO) WHEN MATCHED THEN UPDATE SET a.sal = b.sal WHERE a.empno IN ('7566','7654') -- 只更新指定员工 DELETE WHERE empno = '7654' -- 更新后删除7654员工[^4] ``` ### 四、关键注意事项 1. **一对一限制** 源数据集必须与目标表保持 **一对一关联**,否则执行报错[^5]。 2. **版本兼容性** 早期版本存在BUG(如分区表、并行处理场景),建议检查数据库版本及补丁[^3]。 3. **权限要求** 需对目标表有`INSERT`、`UPDATE`、`DELETE`权限。 4. **空源数据处理** 源数据集为空时可能导致意外行为(部分版本存在匹配逻辑异常)[^3]。 ### 五、典型应用场景 1. 数据仓库的增量加载 2. 多系统间数据同步 3. 批量初始化或更新维度表 4. 避免重复编写`IF EXISTS...UPDATE...ELSE INSERT`逻辑[^2][^5] --- **相关问题** 1. `MERGE INTO`语句在哪些场景下会触发`ORA-30926`错误?如何解决? 2. 如何利用子查询作为`MERGE INTO`的源数据实现动态更新? 3. `MERGE INTO`与`INSERT ALL`+`UPDATE`相比的性能差异? 4. 为什么`MERGE INTO`要求源数据和目标表必须是一对一关系? 5. 如何通过`MERGE INTO`实现“仅当源数据存在时才更新目标表”的逻辑? 6. 是否有替代方案可绕过Oracle早期版本中`MERGE INTO`的BUG?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值