35人参与 • 2026-09-10 • Oracle
在oracle中,常规的dml语句只能完成单一功能,例如insert/delete/update只能三选一,而merge into语句可以同时对一张表进行更新/插入/删除。
merge into常用在数据同步的场景,它会选定一张基表作为数据源,然后与目标表的记录进行匹配,根据匹配的结果,可以对目标表同时进行更新/插入/删除操作。
语法:
merge into target_table using source_table on (join_condition) when matched then update set … [where …] [delete … where …] when not matched then insert (column_list) values (value_list) [where …] log errors into … reject limit [integer|unlimited]
先创建2张表,一张源表,一张目标表:
create table src_table( id number(6), name varchar2(32), salary number(6), bonus number(6)); insert into src_table values(1,'vincent',1000,100); insert into src_table values(2,'victor',2000,200); insert into src_table values(3,'grace',3000,300); create table tgt_table( id number(6), name varchar2(32), age number(6), salary number(6), bonus number(6)); insert into tgt_table values(1,'someone',1,0,0); insert into tgt_table values(3,'someone',3,0,0); insert into tgt_table values(4,'someone',4,0,0); commit;
两张表的数据如下:
select * from src_table; select * from tgt_table;

下面是最基本的用法,利用源表对目标表同时进行更新和插入
merge into tgt_table t using src_table s on (t.id=s.id) when matched then update set t.name=s.name, t.salary=s.salary, t.age=10 when not matched then insert values(s.id,s.name,10,s.salary,s.bonus+50); commit; select * from tgt_table;

对于匹配的记录,可以使用where子句进一步限制范围
merge into tgt_table t using src_table s on (t.id=s.id) when matched then update set t.bonus=s.bonus where s.id>=2; select * from tgt_table order by id;

在update子句后,还可以跟上delete … where …子句,对匹配上的记录进行删除操作
merge into tgt_table t using src_table s on (t.id=s.id) when matched then update set t.bonus=s.bonus+50 where s.id>=3 delete where id>=2; select * from tgt_table order by id;

数据同步的时,源表和目标表的结构/数据类型/约束可能并不一致,这就导致数据同步可能部分失败,现在我们修改tgt表,限制salary字段值不能超过3000,即插入超过3000的数字将失败:
alter table tgt_table modify salary number(6) check(salary<=3000);

首先调用dbms_errlog.create_error_log为tgt_table创建一张错误日志表,表名为errlog:
exec dbms_errlog.create_error_log('tgt_table', 'errlog');
然后在执行merge into 语句时,在最后跟上log errors into子句,如果语句执行过程中遇到错误,则会将错误记录到错误日志中,方便后期排查和修复,这里将tgt_table清空,尝试将src_table的3条数据同步进去,同时salary增加1000
truncate table tgt_table;
merge into tgt_table t
using src_table s on (t.id=s.id)
when not matched then insert values(s.id,s.name,10,s.salary+1000,s.bonus)
log errors into errlog('something is wrong.');
select * from tgt_table;
查询errlog表,可以看到导致失败的原因,id为3的记录,salary在增加1000后为4000,违反了目标表的约束(check salary<=3000):
select * from errlog;

如果我们不想让出现错误的时候语句就回滚,可以在后面跟上一个reject limit n子句,限制只有出现n个以上的错误时才回滚语句:
merge into tgt_table t
using src_table s on (t.id=s.id)
when not matched then insert values(s.id,s.name,10,s.salary+1000,s.bonus)
log errors into errlog('allow one error.') reject limit 1;
select * from tgt_table;
再次查询errlog
select * from errlog;

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论