拉链表
概念
不是技术,而是解决方案
目的:节约存储空间
记录数据在某一时间区间内的状态
以及数据在某一时点上的变化的数据存储方式
也是应需求而产生的技术解决方案
历史数据的两种存储方式
账户ID | 用户 | 状态 | 数据日期 |
001 | 张三 | 1 | 2008-06-27 |
001 | 张三 | 1 | 2008-06-28 |
001 | 张三 | 1 | 2008-06-29 |
001 | 张三 | 1 | 2008-06-30 |
001 | 张三 | 1 | 2008-07-01 |
001 | 张三 | 1 | 2008-07-02 |
001 | 张三 | 1 | 2008-07-03 |
001 | 张三 | 1 | ... |
001 | 张三 | 0 | 2010-02-23 |
001 | 张三 | 0 | 2010-02-24 |
001 | 张三 | 0 | 2010-02-25 |
001 | 张三 | 0 | 2010-02-26 |
001 | 张三 | 0 | ... |
账户ID | 户名 | 状态 | 开始日期 | 结束日期 |
001 | 张三 | 1 | 2008-06-27 | 2010-02-23 |
001 | 张三 | 0 | 2010-02-23 | 2999-12-31 |
流程
- 建立临时表1
用于存放转换,处理后的数据 - 建立临时表2
用于存放比对出的增量数据 - 修改目标表
进行关链更新操作 - 修改目标表
进行开链插入操作
代码实现流程
建立源数据
create table test_src
(
ID varchar2(100),
NAME varchar2(100),
BAL number(20,2)
)
往源中插入数据
insert into test_src
select '1','徐峥',600 from dual
union all
select '2','黄渤',700 from dual
建立目标表
create table test_tag
(
ID varchar2(100),
NAME varchar2(100),
BAL number(20,2),
START_DT date,
END_DT date
)
建立临时表temp1
用于存放原系统数据
--事务临时表
create global temporary table temp1
as select * from test_tag
建立第二个临时表temp2
用于存放对比后的增量或是状态有变化的数据
create global temporary table temp2 --事务临时表
as select * from test_tag
临时表temp1插入数据
此处方便测试,使用前天时间
insert into temp1
select a.*,trunc(sysdate-2,'dd'),to_date('29990101','yyyy/mm/dd')
from test_src a
临时表temp2插入数据
insert into temp2
SELECT *
FROM temp1 t1
WHERE not exists(
SELECT 1
FROM test_tag g
WHERE g.END_DT=to_date('29990101','yyyy/mm/dd')
and t1.id=g.id
and t1.bal=g.bal);
关链
此处方便测试,使用前天时间
update test_tag a set end_dt=trunc(sysdate-2,'dd')
where exists (select 1 from temp2 b where a.id=b.id)
and END_DT = to_date('29990101','yyyy/mm/dd');
开链
insert into test_tag
select * from temp2;
commit;
查看目标表
SQL> select * from test_tag;
ID NAME BAL START_DT END_DT
----- ---------- --- ----------- -----------
2 黄渤 700.00 2020/3/23 2999/1/1
1 徐峥 600.00 2020/3/23 2999/1/1
修改数据再次测试
修改和插入数据
update test_src
set bal=2700
where id=2;
insert into test_src
values(3,'黄晓明',1000);
commit;
SQL> select * from test_src;
ID NAME BAL
--- -------- -----------
1 徐峥 600.00
2 黄渤 2700.00
3 黄晓明 1000.00
插入到临时表temp1
此时为测试方便使用昨天时间
insert into temp1
select a.*,trunc(sysdate-1,'dd'),to_date('29990101','yyyy/mm/dd')
from test_src a
插入到临时表temp2
insert into temp2
SELECT *
FROM temp1 t1
WHERE not exists(
SELECT 1
FROM test_tag g
WHERE g.END_DT=to_date('29990101','yyyy/mm/dd')
and t1.id=g.id
and t1.bal=g.bal);
关链
update test_tag a set end_dt=trunc(sysdate-1,'dd')
where exists (select 1 from temp2 b where a.id=b.id)
and END_DT = to_date('29990101','yyyy/mm/dd');
开链
insert into test_tag
select * from temp2;
commit;
查看目标表
SQL> select * from test_tag;
ID NAME BAL START_DT END_DT
---- -------- ---------- --------- -------------
3 黄晓明 1000.00 2020/3/24 2999/1/1
2 黄渤 2700.00 2020/3/24 2999/1/1
2 黄渤 700.00 2020/3/23 2020/3/24
1 徐峥 600.00 2020/3/23 2999/1/1
应用
查看23号大家的余额情况
SQL> select * from test_tag
2 where start_dt<=to_date('20200323','yyyy/mm/dd')
3 and
4 end_dt>to_date('20200323','yyyy/mm/dd')
5 ;
ID NAME BAL START_DT END_DT
--- ----- -------- ---------- -------------
2 黄渤 700.00 2020/3/23 2020/3/24
1 徐峥 600.00 2020/3/23 2999/1/1
开始时间<=20200323
结束时间>20200323