Time Zipper(Oracle数仓历史拉链表算法)
拉链表是针对数据仓库设计中表存储数据的方式而定义的,所谓拉链,就是记录历史;记录一个事物从开始,一直到当前状态的所有变化的信息;与之相对应的算法就叫拉链算法!
算法介绍:
1采集当日全量数据到ND(NewDay)表;
2从历史表中取出昨日全量数据存储到OD(OldDay)表;
3(ND-OD)就是当日新增和变化的数据,也就是当天的增量,用W_I表示;
4(OD-ND)为状态到此结束需要封链的数据,用W_U表示;
5将W_I表的内容全部插入到历史表中,这些是新增记录,start_date为当天,而end_date为max值;
6对历史表进行W_U部份的更新操作,start_date保持不变,而end_date改为当天,也就是封链操作!
ND-OD两个表进行全字段比较(主键和属性)但是(START_DATE&END_DATE)除外。将结果记录到W_I表中
OD-ND两个表进行全字段比较(主键和属性)同样(START_DATE&END_DATE)除外。将结果记录到W_U表中
实践举例:
declare
P_ETLDATE varchar2(10) :='20090920';
begin
--清空临时表
execute immediate 'truncate table TMP_T02_CUSTOMER_STATUS_H_PRE';
execute immediate 'truncate table TMP_T02_CUSTOMER_STATUS_H_CUR';
execute immediate 'truncate table TMP_T02_CUSTOMER_STATUS_H_INS';
execute immediate 'truncate table TMP_T02_CUSTOMER_STATUS_H_UPD';
--恢复数据
DELETE FROM EDW_T02_CUSTOMER_STATUS_H
WHERE START_DATE = TO_DATE(P_ETLDATE,'YYYY-MM-DD')
;
UPDATE EDW_T02_CUSTOMER_STATUS_H
SET END_DATE = TO_DATE('30001231','YYYY-MM-DD')
WHERE END_DATE = TO_DATE(P_ETLDATE,'YYYY-MM-DD')
;
--取目标表中的上日状态正常的数据
INSERT INTO TMP_T02_CUSTOMER_STATUS_H_PRE
(cust_no --客户编号
,cust_status_type_cd --客户状态类型
,cust_status_cd --客户状态
,start_date --开始日期
,end_date --结束日期
)
SELECT
cust_no
,cust_status_type_cd
,cust_status_cd
,start_date
,end_date
FROM EDW_T02_CUSTOMER_STATUS_H
WHERE END_DATE = TO_DATE('30001231','YYYY-MM-DD')
;
--从源表中获取当日数据
INSERT INTO TMP_T02_CUSTOMER_STATUS_H_CUR
(cust_no
,cust_status_type_cd
,cust_status_cd
,start_date
,end_date
)
SELECT
'CIF'||CUST_NO
,'1'
,CUST_STATUS
,TO_DATE(P_ETLDATE,'YYYY-MM-DD')
,TO_DATE('30001231','YYYY-MM-DD')
FROM ODS_CIF_C_CUST
;
--获取增量数据
INSERT INTO TMP_T02_CUSTOMER_STATUS_H_INS
(cust_no
,cust_status_type_cd
,cust_status_cd
,start_date
,end_date
)
SELECT
a.cust_no
,a.cust_status_type_cd
,a.cust_status_cd
,a.start_date
,a.end_date
FROM TMP_T02_CUSTOMER_STATUS_H_CUR a
LEFT JOIN TMP_T02_CUSTOMER_STATUS_H_PRE b
ON a.cust_no=b.cust_no
AND a.cust_status_type_cd=b.cust_status_type_cd
AND a.a.cust_status_cd=b.a.cust_status_cd
WHERE b.cust_no IS NULL
;
--获取需要更新的数据(先删除再插入)
INSERT INTO TMP_T02_CUSTOMER_STATUS_H_UPD
(cust_no
,cust_status_type_cd
,cust_status_cd
,start_date
,end_date
)
SELECT
a.cust_no
,a.cust_status_type_cd
,a.cust_status_cd
,a.start_date
,a.end_date
FROM TMP_T02_CUSTOMER_STATUS_H_PRE a
LEFT JOIN TMP_T02_CUSTOMER_STATUS_H_CUR b
ON a.cust_no=b.cust_no
AND a.cust_status_type_cd=b.cust_status_type_cd
AND a.a.cust_status_cd=b.a.cust_status_cd
WHERE b.cust_no IS NULL
;
--删除目标表中需要更新的数据(筛选条件用主键+开始时期)
DELETE FROM EDW_T02_CUSTOMER_STATUS_H
WHERE (cust_no,cust_status_type_cd,Start_Date)
IN (SELECT cust_no
,cust_status_type_cd
,Start_Date
FROM TMP_T02_CUSTOMER_STATUS_H_UPD
)
;
--向目标表中插入更新数据
INSERT INTO EDW_T02_CUSTOMER_STATUS_H
(cust_no
,cust_status_type_cd
,cust_status_cd
,start_date
,end_date
)
SELECT
cust_no
,cust_status_type_cd
,cust_status_cd
,start_date
,TO_DATE(P_ETLDATE,'YYYY-MM-DD')
FROM TMP_T02_CUSTOMER_STATUS_H_UPD
;
--向目标表中插入新增数据
INSERT INTO EDW_T02_CUSTOMER_STATUS_H
(cust_no
,cust_status_type_cd
,cust_status_cd
,start_date
,end_date
)
SELECT
cust_no
,cust_status_type_cd
,cust_status_cd
,TO_DATE(P_ETLDATE,'YYYY-MM-DD')
,TO_DATE('30001231','YYYY-MM-DD')
FROM TMP_T02_CUSTOMER_STATUS_H_INS
;
end;
注:TMP_T02_CUSTOMER_STATUS_H_PRE,TMP_T02_CUSTOMER_STATUS_H_CUR,TMP_T02_CUSTOMER_STATUS_H_INS,TMP_T02_CUSTOMER_STATUS_H_UPD是四个临时表,它们的表结构与目标表一致;此表的主键是cust_no、cust_status_type_cd、start_date;属性字段是cust_status_cd;数据比对的时候是根据目标表的主键(及属性字段)来关联LEFT JOIN ON条件的,其中start_date不能带进去;封链更新的时候采用先删除再插入的方式。
说明:
如果源表的非主键字段进行了更新,则进行ETL转换的时候,更新的内容将转不到目标表中?所以,在进行left join关联的时候,也要把非主键的属性字段关联进去,方可解决此问题。
更多推荐

所有评论(0)