拉鏈表
概念
不是技術,而是解決方案
目的:節約存儲空間
記錄數據在某一時間區間內的狀態
以及數據在某一時點上的變化的數據存儲方式
也是應需求而產生的技術解決方案
歷史數據的兩種存儲方式
賬戶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