You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测随时间变化的表中删除行并同步更新目标表

Oracle实现目标表与源表全量同步(含变更捕获)

我们有source和destination两张数据库表,source表会随时间执行DML操作发生变化。为便于演示,我们创建source_before和source_after两张表模拟source表的前后状态。


步骤1:搭建测试环境

创建并初始化模拟源表

-- 创建source_before,模拟source表初始状态
create table source_before (
id int,
name varchar2(40),
creation_time date
);

-- 插入初始数据
insert all 
into source_before values (1,'bola','01-Jan-20') 
into source_before values (2,'gol','02-Jan-21') 
into source_before values (3,'cav','02-Jan-23')
into source_before values (4,'bhf','02-Jan-25')
select * from dual;

-- 查询source_before数据
select * from source_before;

执行结果:

1   bola 01-JAN-20
2   gol 02-JAN-21
3   cav 02-JAN-23
4   bhf 02-JAN-25
-- 创建source_after,模拟source表变更后的状态
create table source_after (
id int,
name varchar2(40),
creation_time date
);

-- 插入变更后的数据
insert all 
into source_after values (1,'bola','01-Jan-20') 
into source_after values (2,'gol','02-Jan-21') 
into source_after values (5,'zzz','02-Jan-28')
into source_after values (6,'sss','02-Jan-25')
select * from dual;

-- 查询source_after数据
select * from source_after;

执行结果:

1   bola 01-JAN-20
2   gol 02-JAN-21
5   zzz 02-JAN-28
6   sss 02-JAN-25

创建并初始化目标表

-- 创建destination表,初始状态与source_before完全一致
create table destination (
id int,
name varchar2(40),
creation_time date
);

-- 插入初始数据
insert all 
into destination values (1,'bola','01-Jan-20') 
into destination values (2,'gol','02-Jan-21') 
into destination values (3,'cav','02-Jan-23')
into destination values (4,'bhf','02-Jan-25')
select * from dual;

-- 查询destination初始数据
select * from destination;

执行结果:

1   bola 01-JAN-20
2   gol 02-JAN-21
3   cav 02-JAN-23
4   bhf 02-JAN-25

步骤2:普通MERGE语句的局限

使用常规MERGE仅能处理新增和更新操作,无法自动删除destination中source_after不存在的行:

merge into destination d
using (select * from source_after) sa on (d.id = sa.id)
when matched then update
set 
d.name = sa.name,
d.creation_time = sa.creation_time 
when not matched then
insert (
d.id,
d.name,
d.creation_time
)
values
(
sa.id,
sa.name,
sa.creation_time
);

-- 查询执行后的destination数据
select * from destination;

执行结果:

1   bola 01-JAN-20
2   gol 02-JAN-21
3   cav 02-JAN-23
4   bhf 02-JAN-25
6   sss 02-JAN-25
5   zzz 02-JAN-28

可见新增行已插入,但id=3、4的冗余行未被删除,无法实现全量同步。


步骤3:实现全量同步并捕获变更记录

要完成完全同步,需同时处理更新、新增、删除操作,并捕获所有变更行。我们采用「MERGE处理新增/更新 + DELETE清理冗余行」的组合方案,配合RETURNING子句记录变更。

3.1 创建变更日志表

用于存储新增、删除的行记录:

create table change_log (
change_type varchar2(10), -- 标记变更类型:INSERT/DELETE
id int,
name varchar2(40),
creation_time date,
change_timestamp timestamp default systimestamp -- 记录变更时间
);

3.2 执行MERGE处理新增与更新,捕获新增行

declare
  type change_rec is record (
    id int,
    name varchar2(40),
    creation_time date
  );
  type change_tab is table of change_rec;
  v_changes change_tab;
begin
  merge into destination d
  using (select * from source_after) sa on (d.id = sa.id)
  when matched then update
  set d.name = sa.name, d.creation_time = sa.creation_time
  when not matched then
  insert (d.id, d.name, d.creation_time)
  values (sa.id, sa.name, sa.creation_time)
  returning d.id, d.name, d.creation_time bulk collect into v_changes;
  
  -- 将新增行写入变更日志
  forall i in 1..v_changes.count
    insert into change_log (change_type, id, name, creation_time)
    values ('INSERT', v_changes(i).id, v_changes(i).name, v_changes(i).creation_time);
    
  commit;
end;
/

3.3 删除冗余行,捕获删除记录

declare
  type change_rec is record (
    id int,
    name varchar2(40),
    creation_time date
  );
  type change_tab is table of change_rec;
  v_changes change_tab;
begin
  delete from destination d
  where not exists (select 1 from source_after sa where sa.id = d.id)
  returning d.id, d.name, d.creation_time bulk collect into v_changes;
  
  -- 将删除行写入变更日志
  forall i in 1..v_changes.count
    insert into change_log (change_type, id, name, creation_time)
    values ('DELETE', v_changes(i).id, v_changes(i).name, v_changes(i).creation_time);
    
  commit;
end;
/

3.4 验证同步结果

查询destination表,确认与source_after完全一致:

select * from destination;

结果:

1   bola 01-JAN-20
2   gol 02-JAN-21
5   zzz 02-JAN-28
6   sss 02-JAN-25

查询变更日志,查看捕获的记录:

select * from change_log;

结果示例:

INSERT  5   zzz 02-JAN-28  2024-05-20 15:30:00.123
INSERT  6   sss 02-JAN-25  2024-05-20 15:30:00.123
DELETE  3   cav 02-JAN-23  2024-05-20 15:31:00.456
DELETE  4   bhf 02-JAN-25  2024-05-20 15:31:00.456

内容的提问来源于stack exchange,提问作者moth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 19:21:09