拉链表如何实现
什么是拉链表
参考0:https://zhuanlan.zhihu.com/p/578804017
参考1:https://blog.csdn.net/weixin_39948277/article/details/111749235
适用场景:适用于大量数据,少量变更的应用场景
拉链表如何实现
参考0:https://blog.csdn.net/yuxiu_1191610370/article/details/116117008
拉链表实现方式:
1)更新end_date
2)插入变更的记录
3)插入新纪录
链表就是先更新历史数据,再插入变更数据
第一步:创建用于记录用户邮箱变更的拉链表:
1.1 创建拉链表 user_email_history, 假设目标表叫做 user_info (u_id ,u_name , u_sex ,u_birthday, u_address , u_email , u_tel ,u_update )
create table user_email_history
(user_id number(10), -- 用户id
user_email varchar2(20), --用户邮箱
beg_date date, --上一次更新时间
end_date date ) --最后一次更新时间(最后一次更新后,我们将这个时间设置为 5000/12/31,用于查找链表中最后一批更新的数据)
第二步:找到 拉链表中最后一批更新的数据 且 该数据已经发生了变更 , 在拉链表中更新该数据的end_date,使之与目标表时间一致
update user_email_history as his
set his.end_date = (select u_update from user_info where his.id = u_id )
where exist (select u_update
from user_info as u
where his.user_id = u.u_id -- 用户id 相同
and his.user_email != u.u_email -- 用户 邮箱不同
and his.end_date = to_date ('5000/12/31','yyyy/mm/dd')); -- 链表中最后一次更新的数据
commit;
第三步:向拉链表中插入目标表发生变更的数据,最后时间设置为 5000/12/31
insert into user_email_history
select u_id,
u_email,
u_update as beg_date,
to_date('5000/12/31', 'yyyy/mm/dd') as end_date
from user_info u
where exists (select *
from user_email_history as his
where u.u_id = his.user_id
and u.u_email != his.user_email
and u.u_update = his.end_date) --因上一步更新了拉链表的需要更新数据的最后时间,这里进行时间等值判断就能找到这部分数据
and
--下面这个条件是防止目标表数据变更一次,链表多次更新造成数据重复(这步一定要加,一定要加,一定要加,重要的事情讲三遍)
not exists
(select *
from user_email_history as his
where u.u_id = his.his.user_id
and u.u_email = his.user_email
and his.end_date = to_date('5000/12/31', 'yyyy/mm/dd'));
commit;
第四步:向链表中插入 目标表中新出现的数据(也就是链表中没有这个记录的新数据)
insert into user_email_history as his
select u.u_id,
u.u_email,
u.update as beg_date,
to_date('5000/12/31', 'yyyy/mm/dd') as end_date
from user_info as u
where not exists (select * from user_email_history as where u.u_id = user_id);
commit;
总结一下:链表就是先更新历史数据,再插入变更数据
要注意的就是第三步一定要加过滤条件防止目标表更新一次,链表多次更新,造成数据错误的情况!