sql - 检测表中随时间变化的已删除行

标签 sql oracle

假设我有两个表 sourcedestination 。源表随着时间的推移而变化,例如从一天到另一天。举个例子,我将在此处创建两个表 source_beforesource_after 但实际上,这是同一个表,其中随着时间的推移会发生一些 DML 语句。

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;

select * from source_before;


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



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;


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 存在时已更新,因此包含与 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;

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

现在,如果我想将 destination 更新为 source_after 创建的新更改,即删除 id 3 和 4 以及插入id 5和6。我可以用这个语句来执行插入操作,但不能执行删除操作。

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

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

我们可以看到行56已插入,但该语句无法删除行3 4. 。因此,目标是反射(reflect)更改并能够捕获 source 表上的插入和删除。因此,destination 的结果应该是:

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

最佳答案

您将需要一种或另一种数据库链接,或者您将需要像 NiFi 或类似的中间件解决方案来充当中介。

在任何一种情况下,如果使用数据库链接,您都需要合并来复制插入和更新(例如示例中的操作),并需要一个单独的删除命令来处理删除。您无法通过一个命令完成所有操作。如果您无法修改目标数据库的结构,那么您必须从 Oracle 源数据库创建一个链接,并使用类似这样的内容(不保证性能):

merge into destination@dblink 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
  );

delete from destination@dblink where id not in 
    (select id from source_after);

如果您不想要直接的数据库链接(这并不总是可行或不切实际),则可以在源数据库中使用触发器来记录各种事务及其详细信息,例如审计表中的相关列值(Oracle 不支持在最新版本中没有方便的更改数据捕获功能,因此您必须自己制作)。然后使用 NiFi 等外部工具读取该表,将审核记录转换为可以排队并应用于目标数据库的单独 DML 命令。使用 NiFi 有许多不同的方法可以做到这一点,其他数据管道工具也可以做同样的事情,所以我无法详细说明,但希望您能明白。

此外,如果使用像 NiFi 这样的外部工具,那么预计同步过程在某些时候会失败并且您需要对目标进行完全刷新的可能性:规划一种可以进行完全刷新的机制(在事实上首先这样做)以及随着时间的推移保持增量更新。

关于sql - 检测表中随时间变化的已删除行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75007899/

相关文章:

sql - 仅从同一表中的其他某些行中减去仅某些行的聚合?

c# - 在 asp.net 中使用 sqldatasource 时出现 mysql sntax 错误

sql - 从 ORACLE 数据库中选择记录

sql - 将 .sql 文件中的语句插入 Oracle 数据库,结果为 ORA-01704 : string literal too long

oracle - 确定Oracle日期是否在周末?

mysql - 评选薪资最高的10名员工

mysql - SQL中如何统计多列出现的次数

mysql - 基于列计算非连续行集的优化方法

sql - 授予对架构上任何表/ View 的选择

java - mysql 和 oracle 是否有用于自动生成的唯一标识以在 pojo 中使用的通用注释?