当前位置:   article > 正文

数据仓库_拉链表_拉链表实现思路_数仓拉链表

数仓拉链表

本篇文章,主要讲解

 1.什么是拉链表 以及 拉链表示例

 2.不同原始表情况下,拉链表如何构建

首先介绍下什么是拉链表

1.什么是拉链表 以及 拉链表示例

什么是拉链表

     当维度数据发生变化时,将旧数据置为失效,将更改后的数据当作新的记录插入到维度表中,并开始生效,这样能够记录数据在某种粒度上的变化历史。

拉链表的示例

      请参见我的另一篇文章

 数据仓库_缓慢渐变维_拉链表(全揭秘)_拉链表中的代理主键_高达一号的博客-CSDN博客

 2.不同原始表情况下,拉链表如何构建

1.第一种情况,规范的表

    什么是规范的表,规范的意思是原始表的含有 create_time , update_time  

假设原始表到数仓的表,每天全量的采集方式

下面我们构建表,并且插入测试数据

  1. use data_warehouse_test;
  2. CREATE TABLE IF NOT EXISTS user_zipper_org (
  3. user_id BIGINT COMMENT '用户id'
  4. ,user_name STRING COMMENT '用户姓名'
  5. ,create_time DATE COMMENT '创建时间'
  6. ,update_time DATE COMMENT '修改时间'
  7. )
  8. PARTITIONED BY(
  9. pt STRING COMMENT '数据分区'
  10. )
  11. STORED AS ORC
  12. ;
  13. ALTER TABLE user_zipper_org DROP IF EXISTS PARTITION (pt = '20200320');
  14. ALTER TABLE user_zipper_org DROP IF EXISTS PARTITION (pt = '20200321');
  15. INSERT INTO TABLE user_zipper_org PARTITION (pt = '20200320')
  16. VALUES
  17. (1, 'szh', '2020-01-01', '2020-01-01')
  18. ,(2, 'yuqin', '2020-01-01', '2020-01-01')
  19. ,(3, 'heping', '2020-01-01', '2020-01-01')
  20. ,(4, 'quxingma', '2020-01-01', '2020-01-01')
  21. ,(5, 'zhouzhou', '2020-01-01', '2020-01-01')
  22. ;
  23. INSERT INTO TABLE user_zipper_org PARTITION (pt = '20200321')
  24. VALUES
  25. (1, 'szh2', '2020-01-01', '2020-03-21')
  26. ,(2, 'yuqin', '2020-01-01', '2020-01-01')
  27. ,(3, 'heping3', '2020-01-01', '2020-03-21')
  28. ,(4, 'quxingma', '2020-01-01', '2020-01-01')
  29. ,(5, 'zhouzhou', '2020-01-01', '2020-01-01')
  30. ,(6, 'newuser', '2020-03-21', '2020-03-21')
  31. ;

构建最终拉链表,这里面为了保证数据安全,我们最终的拉链表是一张分区表

首先,由于是从20200320 开始构建的拉链表,那么原始表所有的数据都相当于当前生效的数据,我们根据这些数据构建20200320的最终拉链表数据。

其次,我们需要通过 最终表 20200320 分区的数据去构建临时表。

上面两个步骤的SQL如下

  1. use data_warehouse_test;
  2. CREATE TABLE IF NOT EXISTS user_zipper_final
  3. (
  4. user_id BIGINT COMMENT '用户id'
  5. ,user_name STRING COMMENT '用户姓名'
  6. ,create_time DATE COMMENT '创建时间'
  7. ,update_time DATE COMMENT '修改时间'
  8. ,start_date DATE COMMENT '生效时间'
  9. ,end_date DATE COMMENT '失效时间'
  10. )
  11. PARTITIONED BY(
  12. pt STRING COMMENT '数据分区'
  13. );
  14. INSERT OVERWRITE TABLE user_zipper_final PARTITION (pt = '20200320')
  15. SELECT
  16. org.user_id
  17. ,org.user_name
  18. ,org.create_time
  19. ,org.update_time
  20. ,'2020-03-20' AS start_date
  21. ,'9999-12-31' AS end_date
  22. FROM user_zipper_org AS org
  23. WHERE pt = '20200320'
  24. ;
  25. DROP TABLE IF EXISTS tmp_user_zipper_mid;
  26. CREATE TABLE tmp_user_zipper_mid AS
  27. SELECT
  28. org.user_id
  29. ,org.user_name
  30. ,org.create_time
  31. ,org.update_time
  32. ,org.start_date
  33. ,org.end_date
  34. FROM user_zipper_final AS org
  35. WHERE pt = '20200320'
  36. ;

关键的步骤,我们根据 20200321 发生变动的数据 (新增的 与 修改的)

新增的 create_time 为 2020-03-21

修改的 update_time 为 2020-03-21

和 20200320 的全量拉链表数据,去构建 20200321 的拉链表数据 (这里我们先存储为临时表,即中间表)

首先,新增与变动的数据我们可以通过这种方式获得

  1. 2020-03-21 发生变动的数据
  2. SELECT
  3. org.user_id
  4. ,org.user_name
  5. ,org.create_time
  6. ,org.update_time
  7. ,'2020-03-20' AS start_date
  8. ,'9999-12-31' AS end_date
  9. FROM user_zipper_org AS org
  10. WHERE pt = '20200321'
  11. AND (
  12. (
  13. create_time = '2020-03-21'
  14. )
  15. OR
  16. (
  17. update_time = '2020-03-21'
  18. )
  19. )
  20. ;

20200321 的全量拉链表数据,可以通过以下方式构建

  1. use data_warehouse_test;
  2. DROP TABLE IF EXISTS tmp_user_zipper_mid;
  3. CREATE TABLE tmp_user_zipper_mid AS
  4. SELECT *
  5. FROM
  6. (
  7. SELECT
  8. final.user_id
  9. ,final.user_name
  10. ,final.create_time
  11. ,final.update_time
  12. ,final.start_date
  13. ,CAST (
  14. (
  15. CASE
  16. WHEN
  17. (
  18. new_data.user_id IS NOT NULL
  19. AND
  20. final.end_date >= '2020-03-21'
  21. )
  22. THEN '2020-03-20'
  23. ELSE final.end_date
  24. END
  25. )
  26. AS DATE
  27. )
  28. AS end_date
  29. FROM
  30. user_zipper_final AS final
  31. LEFT JOIN (
  32. SELECT
  33. org.user_id
  34. ,org.user_name
  35. ,org.create_time
  36. ,org.update_time
  37. FROM user_zipper_org AS org
  38. WHERE pt = '20200321'
  39. AND (
  40. (
  41. create_time = '2020-03-21'
  42. )
  43. OR
  44. (
  45. update_time = '2020-03-21'
  46. )
  47. )
  48. ) AS new_data
  49. ON new_data.user_id = final.user_id
  50. WHERE final.pt = '20200320'
  51. UNION ALL
  52. SELECT
  53. new_data.user_id
  54. ,new_data.user_name
  55. ,new_data.create_time
  56. ,new_data.update_time
  57. ,CAST( '2020-03-21' AS DATE ) AS start_date
  58. ,CAST ('9999-12-31' AS DATE ) AS end_date
  59. FROM (
  60. SELECT
  61. org.user_id
  62. ,org.user_name
  63. ,org.create_time
  64. ,org.update_time
  65. FROM user_zipper_org AS org
  66. WHERE pt = '20200321'
  67. AND (
  68. (
  69. create_time = '2020-03-21'
  70. )
  71. OR
  72. (
  73. update_time = '2020-03-21'
  74. )
  75. )
  76. ) AS new_data
  77. ) AS tmp
  78. ;

最后,我们把临时表的结果插入到新的拉链表分区。

然后,我们查验下数据 (

1.获取最新的拉链表分区数据

2.通过拉链表,获取2020-03-20的数据

3.通过拉链表,获取2020-03-21的数据

  1. use data_warehouse_test;
  2. INSERT OVERWRITE TABLE user_zipper_final PARTITION (pt = '20200321')
  3. SELECT
  4. *
  5. FROM tmp_user_zipper_mid
  6. ;
  7. SELECT *
  8. FROM user_zipper_final
  9. WHERE pt = '20200321'
  10. ;
  11. SELECT *
  12. FROM user_zipper_final
  13. WHERE pt = '20200321'
  14. AND start_date <= '2020-03-20'
  15. AND end_date >= '2020-03-20'
  16. ;
  17. SELECT *
  18. FROM user_zipper_final
  19. WHERE pt = '20200321'
  20. AND start_date <= '2020-03-21'
  21. AND end_date >= '2020-03-21'
  22. ;

2.第二种情况,非规范的原始表

     什么是非规范的原始表,就是原始表中不存在 create_time 或者 update_time 。 或者更甚者  2者都不存在,这样的情况下,我们该如何去构建拉链表呢?

我们细致的去分析这个问题,如何解决?

首先,我们可以看到通过单一的create_time 或者 update_time ,我们无法分辨发生变动的数据。

由此,我们的思路是构建一列,去标识 发生变动的数据。

我们选择将所有列取 md5 值的方式!!!!

假设我们的原始表有以下几列,

user_id, user_name, create_time

则 MD5(CONCAT(user_id, user_name, create_time))  

假设,我们已经有初始化的拉链表了,那么难点就在于如何获取发生变动的数据 (新增的 与 修改的)

获取发生变动的数据SQL 如下:

  1. SELECT
  2. ta.*
  3. FROM
  4. (
  5. SELECT
  6. user_id
  7. ,user_name
  8. ,create_time
  9. ,MD5(CONCAT(user_id,user_name,create_time)) AS user_flag
  10. FROM user_zipper_org
  11. WHERE pt = '20200321'
  12. ) AS ta
  13. LEFT JOIN (
  14. SELECT
  15. user_id
  16. ,user_flag
  17. FROM user_zipper_final
  18. WHERE pt = '20200320'
  19. AND start_date <= '2020-03-20'
  20. AND end_date >= '2020-03-20'
  21. ) AS tb
  22. ON ta.user_id = tb.user_id
  23. AND ta.user_flag != tb.user_flag
  24. ;

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/255325?site
推荐阅读
相关标签
  

闽ICP备14008679号