拉链表是针对数据仓库设计中表存储数据的方式而定义的,所谓拉链,就是记录历史;记录一个事物从开始,一直到当前状态的所有变化的信息;与之相对应的算法就叫拉链算法!


算法介绍:


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关联的时候,也要把非主键的属性字段关联进去,方可解决此问题。

更多推荐