【转】数据仓库拉链算法在ORACLE中的实现

1、 拉链算法用到的相关表结构

建表脚本(源表、目的表、临时表).sql

 

[c-sharp] view plain  copy  print ?
  1. --生成目标表  
  2. create table EDW_T100_STATUS_H  
  3. (  
  4.   ID         VARCHAR2(8) not null,  
  5.   STATUS     VARCHAR2(8) not null,  
  6.   START_DATE DATE not null,  
  7.   END_DATE   DATE not null  
  8. )  
  9. ;  
  10. --生成源表  
  11. create table ODS_XT_ZT  
  12. (  
  13.   ID            VARCHAR2(8),  
  14.   STATUS        VARCHAR2(8),  
  15.   ODS_DATA_DATE VARCHAR2(8)  
  16. )  
  17. ;  
  18. --生成数据恢复机制用的临时表  
  19. create global temporary table TMP_T100_STATUS_H  
  20. (  
  21.   ID         VARCHAR2(8) not null,  
  22.   STATUS     VARCHAR2(8) not null,  
  23.   START_DATE DATE not null,  
  24.   END_DATE   DATE not null  
  25. )  
  26. on commit delete rows;  
  27. --生成存放历史的临时表  
  28. create global temporary table TMP_T100_STATUS_H_PRE  
  29. (  
  30.   ID         VARCHAR2(8) not null,  
  31.   STATUS     VARCHAR2(8) not null,  
  32.   START_DATE DATE not null,  
  33.   END_DATE   DATE not null  
  34. )  
  35. on commit delete rows;  
  36. --生成存放当前数据的临时表  
  37. create global temporary table TMP_T100_STATUS_H_CUR  
  38. (  
  39.   ID         VARCHAR2(8) not null,  
  40.   STATUS     VARCHAR2(8) not null,  
  41.   START_DATE DATE not null,  
  42.   END_DATE   DATE not null  
  43. )  
  44. on commit delete rows;  
  45. --生成存放新增数据(包含:1、CUR中有而PRE中没有的数据;2、CUR中有PRE中也有,但属性值有更新的,也需要新增开链的数据)的临时表  
  46. create global temporary table TMP_T100_STATUS_H_INS  
  47. (  
  48.   ID         VARCHAR2(8) not null,  
  49.   STATUS     VARCHAR2(8) not null,  
  50.   START_DATE DATE not null,  
  51.   END_DATE   DATE not null  
  52. )  
  53. on commit delete rows;  
  54. --生成存放需要关链数据(包含:1、PRE中有而CUR中没有;2、PRE中有CUR中也有,但属性值有更新,需要将老数据关链的数据)的临时表  
  55. create global temporary table TMP_T100_STATUS_H_UPD  
  56. (  
  57.   ID         VARCHAR2(8) not null,  
  58.   STATUS     VARCHAR2(8) not null,  
  59.   START_DATE DATE not null,  
  60.   END_DATE   DATE not null  
  61. )  
  62. on commit delete rows;  

2、 插入测试数据

INSERT到源表测试数据.sql

 

[c-sharp] view plain  copy  print ?
  1. TRUNCATE TABLE Ods_Xt_Zt;  
  2. INSERT INTO Ods_Xt_Zt(ID,Status,Ods_Data_Date)  
  3. SELECT '1','正常','20100101' FROM dual  
  4. UNION ALL  
  5. SELECT '2','正常','20100101' FROM dual  
  6. UNION ALL  
  7. SELECT '3','正常','20100101' FROM dual  
  8. ;  
  9. INSERT INTO Ods_Xt_Zt(ID,Status,Ods_Data_Date)  
  10. SELECT '1','正常','20100102' FROM dual  
  11. UNION ALL  
  12. SELECT '2','呆滞','20100102' FROM dual  
  13. UNION ALL  
  14. SELECT '4','正常','20100102' FROM dual  
  15. ;  
  16. COMMIT;  
  17. --select * from Ods_Xt_Zt;  

3、 实现拉链算法的代码

拉链过程.sql

 

[c-sharp] view plain  copy  print ?
  1. DECLARE  
  2.  P_ETLDATE      VARCHAR2(8) := '20100102';    --日期参数  
  3.  O_RUNSTATUS    NUMBER;                       --执行结果  
  4.  O_MSG          VARCHAR2(100);                --错误返回  
  5.  --定义存储过程信息  
  6.  V_PROC_NAME       VARCHAR2(50)   := 'P_T100_STATUS_H';  
  7.  V_TABLE_NAME      VARCHAR2(50)   := 'EDW_T100_STATUS_H';  
  8.  V_START_TIMESTAMP TIMESTAMP;                --加载开始时间  
  9.  V_END_TIMESTAMP   TIMESTAMP;                --加载结束时间  
  10.  V_RECORD_NUMBER   INTEGER;                  --记录数  
  11.  --定义错误代码,错误状态  
  12.  V_SQLERRM         VARCHAR2(1000);           --异常信息  
  13.  V_ERR_SQL         VARCHAR2(1000);           --出错位置  
  14.   BEGIN  
  15.   
  16.     --捕获过程开始时间  
  17.     SELECT SYSDATE INTO V_START_TIMESTAMP FROM dual;  
  18.       
  19.     --数据恢复(删除start_date大于当天的数据;将end_date大于当天且不为无限大的数据将end_date更新为无限大)  
  20.     --(更新操作之所以使用先删除再插入而不是直接UPDATE的方式是基于效率的考虑)  
  21.     V_ERR_SQL:='DELETE FROM EDW_T100_STATUS_H';  
  22.     DELETE FROM EDW_T100_STATUS_H  
  23.     WHERE  Start_Date >= TO_DATE(P_ETLDATE,'YYYY-MM-DD')  
  24.     ;  
  25.     V_ERR_SQL:='INSERT INTO TMP_T100_STATUS_H';  
  26.     INSERT INTO TMP_T100_STATUS_H  
  27.     SELECT  *  
  28.     FROM    EDW_T100_STATUS_H  
  29.     WHERE   End_Date >= TO_DATE(P_ETLDATE,'YYYY-MM-DD')  
  30.       AND   End_Date <> TO_DATE('30001231','YYYY-MM-DD')  
  31.     ;  
  32.     V_ERR_SQL:='DELETE FROM EDW_T100_STATUS_H-2';  
  33.     DELETE  FROM EDW_T100_STATUS_H  
  34.     WHERE   End_Date >= TO_DATE(P_ETLDATE,'YYYY-MM-DD')  
  35.       AND   End_Date <> TO_DATE('30001231','YYYY-MM-DD')  
  36.     ;  
  37.     V_ERR_SQL:='INSERT INTO EDW_T100_STATUS_H FROM TMP_T100_STATUS_H';  
  38.     INSERT INTO EDW_T100_STATUS_H  
  39.             (Id  
  40.             ,Status  
  41.             ,Start_Date  
  42.             ,End_Date  
  43.             )  
  44.     SELECT  Id  
  45.             ,Status  
  46.             ,Start_Date  
  47.             ,TO_DATE('30001231','YYYY-MM-DD')  
  48.     FROM    TMP_T100_STATUS_H  
  49.     ;  
  50.   
  51.     --取目标表中的上日状态正常(未被封链,即end_date为最大日期)的数据  
  52.     V_ERR_SQL:='INSERT INTO TMP_T100_STATUS_H_PRE';  
  53.     INSERT INTO TMP_T100_STATUS_H_PRE  
  54.             (Id  
  55.             ,Status  
  56.             ,Start_Date  
  57.             ,End_Date  
  58.             )  
  59.     SELECT  Id  
  60.             ,Status  
  61.             ,Start_Date  
  62.             ,End_Date  
  63.     FROM    EDW_T100_STATUS_H  
  64.     WHERE   END_DATE = TO_DATE('30001231','YYYY-MM-DD')  
  65.     ;  
  66.   
  67.     --从源表中获取当日数据(将CUR中的start_date置为当天,end_date置为最大日期)  
  68.     V_ERR_SQL:='INSERT INTO TMP_T100_STATUS_H_CUR';  
  69.     INSERT INTO TMP_T100_STATUS_H_CUR  
  70.             (Id  
  71.             ,Status  
  72.             ,Start_Date  
  73.             ,End_Date  
  74.             )  
  75.     SELECT  ID  
  76.             ,Status  
  77.             ,TO_DATE(P_ETLDATE,'YYYY-MM-DD')  
  78.             ,TO_DATE('30001231','YYYY-MM-DD')  
  79.     FROM    ODS_XT_ZT  
  80.     WHERE   Ods_Data_Date = P_ETLDATE  
  81.     ;  
  82.   
  83.     --[cur-pre] = 增量数据{需要开链}(包含两部分:1、在CUR不在PRE中的纯新增数据;2、在CUR也在PRE中,但CUR中其属性值有更新。=>关联关系中,有主键,也有属性,才能全部包含这两部分)  
  84.     V_ERR_SQL:='INSERT INTO TMP_T100_STATUS_H_INS';  
  85.     INSERT INTO TMP_T100_STATUS_H_INS  
  86.             (Id  
  87.             ,Status  
  88.             ,Start_Date  
  89.             ,End_Date  
  90.             )  
  91.     SELECT   a1.Id                       
  92.             ,a1.Status      
  93.             ,a1.Start_Date  
  94.             ,a1.End_Date   
  95.     FROM    TMP_T100_STATUS_H_CUR      a1  
  96.     WHERE NOT EXISTS (SELECT 1  
  97.                      FROM    TMP_T100_STATUS_H_PRE    a2  
  98.                      WHERE   a1.Id = a2.Id  
  99.                        AND   a1.Status=a2.Status  
  100.                      )  
  101.     ;  
  102.   
  103.     --[pre - cur] = 要封链的数据(包含两部分:1、在PRE中不在CUR中的纯封链数据;2、在PRE中也在CUR中,但CUR中属性值已经改变。=>关联关系中,有主键,也有属性,才能全部包含这两部分)  
  104.     V_ERR_SQL:='INSERT INTO TMP_T100_STATUS_H_UPD';  
  105.     INSERT INTO TMP_T100_STATUS_H_UPD  
  106.             (Id  
  107.             ,Status  
  108.             ,Start_Date  
  109.             ,End_Date  
  110.             )  
  111.     SELECT  a1.Id                       
  112.             ,a1.Status      
  113.             ,a1.Start_Date  
  114.             ,a1.End_Date   
  115.     FROM    TMP_T100_STATUS_H_PRE                 a1  
  116.     WHERE   NOT EXISTS (SELECT 1  
  117.                    FROM    TMP_T100_STATUS_H_CUR  a3  
  118.                    WHERE   a1.Id = a3.Id  
  119.                    AND     a1.Status = a3.Status  
  120.                    )  
  121.     ;  
  122.   
  123.     --删除目标表中需要更新的数据(采用先删除再插入而不是直接UPDATE的方式,完全出于效率考虑){筛选条件用:主键+开始时间}  
  124.     V_ERR_SQL:='DELETE FROM EDW_T100_STATUS_H';  
  125.     DELETE FROM EDW_T100_STATUS_H  
  126.     WHERE  (Id,Start_Date)  
  127.     IN     (SELECT Id  
  128.                    ,start_date  
  129.            FROM    TMP_T100_STATUS_H_UPD  
  130.            )  
  131.     ;  
  132.   
  133.     --向目标表中插入更新数据(将结束日期值置成当天日期)  
  134.     V_ERR_SQL:='INSERT INTO EDW_T100_STATUS_H FROM TMP_T100_STATUS_H_UPD';  
  135.     INSERT INTO EDW_T100_STATUS_H  
  136.             (Id  
  137.             ,Status  
  138.             ,Start_Date  
  139.             ,End_Date  
  140.             )  
  141.     SELECT  Id  
  142.             ,Status  
  143.             ,Start_Date  
  144.             ,TO_DATE(P_ETLDATE,'YYYY-MM-DD')  
  145.     FROM    TMP_T100_STATUS_H_UPD  
  146.     ;  
  147.   
  148.     --向目标表中插入新增数据  
  149.     V_ERR_SQL:='INSERT INTO EDW_T100_STATUS_H FROM TMP_T100_STATUS_H_INS';  
  150.     INSERT INTO EDW_T100_STATUS_H  
  151.             (Id  
  152.             ,Status  
  153.             ,Start_Date  
  154.             ,End_Date  
  155.             )  
  156.     SELECT  Id  
  157.             ,Status  
  158.             ,TO_DATE(P_ETLDATE,'YYYY-MM-DD')  
  159.             ,TO_DATE('30001231','YYYY-MM-DD')  
  160.     FROM    TMP_T100_STATUS_H_INS  
  161.     ;  
  162.   
  163.       --正常处理  
  164.       V_RECORD_NUMBER := SQL%ROWCOUNT;  
  165.       SELECT SYSDATE INTO V_END_TIMESTAMP FROM dual;  
  166.       INSERT INTO EDW_ETL_LOG_DETAIL(START_TIMESTAMP,END_TIMESTAMP,PROC_NAME,TABLE_NAME,ETL_RECORD_NUM,ETL_MEMO,P_ETLDATE)  
  167.       VALUES (V_START_TIMESTAMP,V_END_TIMESTAMP,V_PROC_NAME,V_TABLE_NAME,V_RECORD_NUMBER,'成功',P_ETLDATE);  
  168.       COMMIT;  
  169.   
  170.       --异常处理  
  171.       EXCEPTION WHEN OTHERS THEN  
  172.       BEGIN  
  173.              ROLLBACK;  
  174.              V_SQLERRM := SQLERRM;  
  175.              INSERT INTO EDW_ETL_LOG_DETAIL(START_TIMESTAMP,END_TIMESTAMP,PROC_NAME,TABLE_NAME,ETL_RECORD_NUM,ETL_MEMO,ERR_MSG,ERR_SQL,P_ETLDATE)  
  176.              VALUES (V_START_TIMESTAMP,V_END_TIMESTAMP,V_PROC_NAME,V_TABLE_NAME,0,'失败',V_SQLERRM,V_ERR_SQL,P_ETLDATE);  
  177.              O_RUNSTATUS := 1;  
  178.              O_MSG := 'PROGRAMMING ERROR HAPPENED!';  
  179.              COMMIT;  
  180.       END;  
  181.   END;  

4、 总结说明

(1)、拉链算法要求提供的数据源最好以全量方式提供;要深入理解[INS=CUR-PRE][UPD=PRE-CUR]所分别包含的两个方面;表UPD及更新特指目标表中需要将end_date从max_date置为p_etldate,与源表中的属性字段更新,目标表需要先关链再开链,有本质区别;相关关键注释,在代码中有详细说明。

(2)、比对,就是全字段比对,包含主键和属性;源数据如果是增量的情况,就没办法给已经删除的记录关链,因为删掉的记录不会再传过来,在源数据的表现上,跟没有变化的数据是一样的,这时的UDP表只包含源数据中有变化的那一部分需要封链的记录,源表中被删除的记录,将永不封链;如果源表有增量传的也有全量传的,那只能作为增量数据来考虑,还要作特殊处理,条件为in(主键)and_not_in(主键+属性)。

(3)、针对不同的源数据供数方式,拉链算法的不同主要体现在INSERT到UPD表的关联上,插入到INS上等,并没有不同

全量的情况:

[c-sharp]view plain copy print?
  1. V_ERR_SQL:='INSERT INTO TMP_T100_STATUS_H_UPD';  
  2. INSERT INTO TMP_T100_STATUS_H_UPD  
  3.         (Id  
  4.         ,Status  
  5.         ,Start_Date  
  6.         ,End_Date  
  7.         )  
  8. SELECT  a1.Id                       
  9.         ,a1.Status      
  10.         ,a1.Start_Date  
  11.         ,a1.End_Date   
  12. FROM    TMP_T100_STATUS_H_PRE                 a1  
  13. WHERE   /*EXISTS (SELECT 1 
  14.                FROM    TMP_T100_STATUS_H_CUR  a2 
  15.                WHERE   a1.Id = a2.Id 
  16.                ) 
  17.   AND */NOT EXISTS (SELECT 1  
  18.                FROM    TMP_T100_STATUS_H_CUR  a3  
  19.                WHERE   a1.Id = a3.Id  
  20.                AND     a1.Status = a3.Status  
  21.                )  
  22. ;  

增量的情况:

[c-sharp]view plain copy print?
  1. V_ERR_SQL:='INSERT INTO TMP_T100_STATUS_H_UPD';  
  2. INSERT INTO TMP_T100_STATUS_H_UPD  
  3.         (Id  
  4.         ,Status  
  5.         ,Start_Date  
  6.         ,End_Date  
  7.         )  
  8. SELECT  a1.Id                       
  9.         ,a1.Status      
  10.         ,a1.Start_Date  
  11.         ,a1.End_Date   
  12. FROM    TMP_T100_STATUS_H_PRE                 a1  
  13. WHERE   EXISTS (SELECT 1  
  14.                FROM    TMP_T100_STATUS_H_CUR  a2  
  15.                WHERE   a1.Id = a2.Id  
  16.                )  
  17.   /*AND NOT EXISTS (SELECT 1 
  18.                FROM    TMP_T100_STATUS_H_CUR  a3 
  19.                WHERE   a1.Id = a3.Id 
  20.                AND     a1.Status = a3.Status 
  21.                )*/  
  22. ;  

有增量也有全量的情况(只能作为增量,且将全量的处理为增量)

[c-sharp]view plain copy print?
  1. V_ERR_SQL:='INSERT INTO TMP_T100_STATUS_H_UPD';  
  2. INSERT INTO TMP_T100_STATUS_H_UPD  
  3.         (Id  
  4.         ,Status  
  5.         ,Start_Date  
  6.         ,End_Date  
  7.         )  
  8. SELECT  a1.Id                       
  9.         ,a1.Status      
  10.         ,a1.Start_Date  
  11.         ,a1.End_Date   
  12. FROM    TMP_T100_STATUS_H_PRE                 a1  
  13. WHERE   EXISTS (SELECT 1  
  14.                FROM    TMP_T100_STATUS_H_CUR  a2  
  15.                WHERE   a1.Id = a2.Id  
  16.                )  
  17.   AND NOT EXISTS (SELECT 1  
  18.                FROM    TMP_T100_STATUS_H_CUR  a3  
  19.                WHERE   a1.Id = a3.Id  
  20.                AND     a1.Status = a3.Status  
  21.                )  
  22. ;  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值