日期:2014-05-16  浏览次数:20401 次

拉链的通常算法

本文中所述的拉链算法,是按照一般性常规思维进行计算的。此过程分3大步,4小步:第一步新增新记录到目标表中,其中包含目标表中没有此主键的记录和断链新增记录两部分内容;第二步将源表已经不存在的记录在目标表中进行行关链;第三步处理变化了属性值的记录:1、关链老数据;2、新开链属性值变化后的数据。
文中所考虑的数据源假设为全量数据;代码中没有体现出数据回滚的过程,这一部分内容可以参考《数据仓库拉链算法在ORACLE中的实现,原文地址:
http://blog.csdn.net/nsj820/article/details/5876895》进行一定程度的修改实现,所用到的测试源表、目标表表结构和数据也可参考此博客中的内容。
算法的性能并没有考虑在内,实际项目过程中可根据需要进行选用;存储过程代码的下方也给出了详尽的数据查看语句和批量调度语句代码,可以测试时参考使用

CREATE OR REPLACE PROCEDURE P_T100_STATUS_H_COMMON(P_ETLDATE VARCHAR2) AS
  --P_ETLDATE VARCHAR2(8) := '20100108';
  --源数据作全量考虑,数据回滚暂未考虑
BEGIN
  --1、EDW表中没有此主键的记录,则确定为新增
  INSERT INTO EDW_T100_STATUS_H
    (ID, STATUS, START_DATE, END_DATE)
    SELECT O.ID,
           O.STATUS,
           TO_DATE(P_ETLDATE, 'YYYYMMDD'),
           TO_DATE('30001231', 'YYYYMMDD')
      FROM ODS_XT_ZT O
     WHERE O.ODS_DATA_DATE = P_ETLDATE
       AND (NOT EXISTS
            (SELECT 1 FROM EDW_T100_STATUS_H T WHERE T.ID = O.ID) OR EXISTS --处理数据断链新增的情况
            (SELECT 1
               FROM (SELECT ID, MAX(END_DATE) END_DATE
                       FROM EDW_T100_STATUS_H
                      GROUP BY ID) T
              WHERE T.ID = O.ID
                AND T.END_DATE < TO_DATE(P_ETLDATE, 'YYYYMMDD')));
  --2、源表中没有此ID了,则进行关链
  UPDATE EDW_T100_STATUS_H T
     SET T.END_DATE = TO_DATE(P_ETLDATE, 'YYYYMMDD')
   WHERE T.END_DATE = TO_DATE('30001231', 'YYYYMMDD')
     AND NOT EXISTS (SELECT 1
            FROM ODS_XT_ZT O
           WHERE T.ID = O.ID
             AND O.ODS_DATA_DATE = P_ETLDATE);
  --3.1、EDW表中有此主键的记录,状态值不同,更新结束日期为当天
  UPDATE EDW_T100_STATUS_H T
     SET T.END_DATE = TO_DATE(P_ETLDATE, 'YYYYMMDD')
   WHERE T.END_DATE = TO_DATE('30001231', 'YYYYMMDD')
     AND EXISTS (SELECT 1
            FROM ODS_XT_ZT O
           WHERE T.ID = O.ID
             AND T.STATUS <> O.STATUS
             AND O.ODS_DATA_DATE = P_ETLDATE);
  --3.2、新增关链后新开链记录
  INSERT INTO EDW_T100_STATUS_H
    (ID, STATUS, START_DATE, END_DATE)
    SELECT O.ID,
           O.STATUS,
           TO_DATE(P_ETLDATE, 'YYYYMMDD'),
           TO_DATE('30001231', 'YYYYMMDD')
      FROM ODS_XT_ZT O
     WHERE EXISTS (SELECT 1
              FROM EDW_T100_STATUS_H T
             WHERE T.ID = O.ID
               AND T.STATUS <> O.STATUS
               AND T.END_DATE = TO_DATE(P_ETLDATE, 'YYYYMMDD') --3.1步刚刚更新过了的日期,而不能是TO_DATE('30001231', 'YYYYMMDD')了
               AND O.ODS_DATA_DATE = P_ETLDATE);

  COMMIT;
END;

  --TRUNCATE TABLE EDW_T100_STATUS_H;
  --SELECT * FROM ODS_XT_ZT ORDER BY 1,3;
  --SELECT * FROM EDW_T100_STATUS_H ORDER BY 1,3;

  /*DECLARE
  BEGIN
    FOR V_KEY IN 20100101 .. 20100107 LOOP
      P_T100_STATUS_H_COMMON(V_KEY);
    END LOOP;
  END;*/
/