oracle實現拉鏈表


拉鏈表

概念

不是技術,而是解決方案
目的:節約存儲空間

記錄數據在某一時間區間內的狀態
以及數據在某一時點上的變化的數據存儲方式

也是應需求而產生的技術解決方案

歷史數據的兩種存儲方式

賬戶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. 建立臨時表1
    用於存放轉換,處理后的數據

  2. 建立臨時表2
    用於存放比對出的增量數據

  3. 修改目標表
    進行關鏈更新操作

  4. 修改目標表
    進行開鏈插入操作

代碼實現流程

建立源數據

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM