拉链表流水表

  1. 1. 全量表:每天的所有的最新状态的数据,  
  2. 2. 增量表:每天的新增数据,增量数据是上次导出之后的新数据。  
  3. 3. 拉链表:维护历史状态,以及最新状态数据的一种表,拉链表根据拉链粒度的不同,实际上相当于快照,只不过做了优化,去除了一部分不变的记录而已,通过拉链表可以很方便的还原出拉链时点的客户记录。  
  4. 4. 流水表: 对于表的每一个修改都会记录,可以用于反映实际记录的变更。   
  5.   
  6. 拉链表通常是对账户信息的历史变动进行处理保留的结果,流水表是每天的交易形成的历史;  
  7. 流水表用于统计业务相关情况,拉链表用于统计账户及客户的情况  
  8. 数据仓库之拉链表(原理、设计以及在Hive中的实现)  
  9.   
  10.   
  11. 在有些情况下,为了保持历史的一些状态,需要用拉链表来做,这样做目的在可以保留所有状态的情况下可以节省空间。  
  12.   
  13. 拉链表适用于以下几种情况吧  
  14.   
  15. 数据量有点大,表中某些字段有变化,但是呢变化的频率也不是很高,业务需求呢又需要统计这种变化状态,每天全量一份呢,有点不太现实,  
  16.   
  17. 不仅浪费了存储空间,有时可能业务统计也有点麻烦,这时,拉链表的作用就提现出来了,既节省空间,又满足了需求。  
  18.   
  19. 一般在数仓中通过增加begin_date,en_date来表示,如下例,后两列是start_date和end_date.  
  20.    
  21. 1  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  22. 1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21  
  23. 1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31  
  24. 2  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  25. 2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31  
  26. 3  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-21  
  27. 3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31  
  28. 4  2016-08-21  2016-08-21  创建 2016-08-21  2016-08-21  
  29. 4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31  
  30. 5  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31  
  31. begin_date表示该条记录的生命周期开始时间,end_date表示该条记录的生命周期结束时间;  
  32.   
  33. end_date = ‘9999-12-31’表示该条记录目前处于有效状态;  
  34.   
  35. 如果查询当前所有有效的记录,则select * from order_his where dw_end_date = ‘9999-12-31′  
  36.   
  37. 如果查询2016-08-21的历史快照,则select * from order_his where begin_date <= ‘2016-08-21′ and end_date >= ‘2016-08-21’  
  38.   
  39. 再简单介绍一下拉链表的更新:  
  40.   
  41. 假设以天为维度,以每天的最后一个状态为当天的最终状态。  
  42.   
  43. 以一张订单表为例,如下是原始数据,每天的订单状态明细  
  44.   
  45. 1   2016-08-20  2016-08-20  创建  
  46. 2   2016-08-20  2016-08-20  创建  
  47. 3   2016-08-20  2016-08-20  创建  
  48. 1   2016-08-20  2016-08-21  支付  
  49. 2   2016-08-20  2016-08-21  完成  
  50. 4   2016-08-21  2016-08-21  创建  
  51. 1   2016-08-20  2016-08-22  完成  
  52. 3   2016-08-20  2016-08-22  支付  
  53. 4   2016-08-21  2016-08-22  支付  
  54. 5   2016-08-22  2016-08-22  创建  
  55. 根据拉链表我们希望得到的是  
  56.   
  57.    
  58. 1  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  59. 1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21  
  60. 1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31  
  61. 2  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  62. 2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31  
  63. 3  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-21  
  64. 3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31  
  65. 4  2016-08-21  2016-08-21  创建 2016-08-21  2016-08-21  
  66. 4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31  
  67. 5  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31  
  68. 可以看出 1,2,3,4每个订单的状态都有,并且也能统计到当前的有效状态。  
  69.   
  70. 本例以hive为例,只考虑到实现,与性能无关  
  71.   
  72. 首先创建表  
  73.    
  74. CREATE TABLE orders (  
  75. orderid INT,  
  76. createtime STRING,  
  77. modifiedtime STRING,  
  78. status STRING  
  79. ) row format delimited fields terminated by '\t'  
  80.    
  81.    
  82. CREATE TABLE ods_orders_inc (  
  83. orderid INT,  
  84. createtime STRING,  
  85. modifiedtime STRING,  
  86. status STRING  
  87. ) PARTITIONED BY (day STRING)  
  88. row format delimited fields terminated by '\t'  
  89.    
  90.    
  91. CREATE TABLE dw_orders_his (  
  92. orderid INT,  
  93. createtime STRING,  
  94. modifiedtime STRING,  
  95. status STRING,  
  96. dw_start_date STRING,  
  97. dw_end_date STRING  
  98. ) row format delimited fields terminated by '\t' ;  
  99. 首先全量更新,我们先到2016-08-20为止的数据。  
  100.   
  101. 初始化,先把2016-08-20的数据初始化进去  
  102.    
  103. INSERT overwrite TABLE ods_orders_inc PARTITION (day = '2016-08-20')  
  104. SELECT orderid,createtime,modifiedtime,status  
  105. FROM orders  
  106. WHERE createtime < '2016-08-21' and modifiedtime <'2016-08-21';  
  107. 刷到dw中  
  108.    
  109. INSERT overwrite TABLE dw_orders_his  
  110. SELECT orderid,createtime,modifiedtime,status,  
  111. createtime AS dw_start_date,  
  112. '9999-12-31' AS dw_end_date  
  113. FROM ods_orders_inc  
  114. WHERE day = '2016-08-20';  
  115.   
  116. 如下结果  
  117.    
  118. select * from dw_orders_his;  
  119. OK  
  120. 1  2016-08-20  2016-08-20  创建 2016-08-20  9999-12-31  
  121. 2  2016-08-20  2016-08-20  创建 2016-08-20  9999-12-31  
  122. 3  2016-08-20  2016-08-20  创建 2016-08-20  9999-12-31  
  123. 剩余需要进行增量更新  
  124.   
  125.    
  126. INSERT overwrite TABLE ods_orders_inc PARTITION (day = '2016-08-21')  
  127. SELECT orderid,createtime,modifiedtime,status  
  128. FROM orders  
  129. WHERE (createtime = '2016-08-21'  and modifiedtime = '2016-08-21') OR modifiedtime = '2016-08-21';  
  130.    
  131. select * from ods_orders_inc where day='2016-08-21';  
  132. OK  
  133. 1  2016-08-20  2016-08-21  支付 2016-08-21  
  134. 2  2016-08-20  2016-08-21  完成 2016-08-21  
  135. 4  2016-08-21  2016-08-21  创建 2016-08-21  
  136. 先放到增量表中,然后进行关联到一张临时表中,在插入到新表中  
  137.   
  138.    
  139. DROP TABLE IF EXISTS dw_orders_his_tmp;  
  140. CREATE TABLE dw_orders_his_tmp AS  
  141. SELECT orderid,  
  142. createtime,  
  143. modifiedtime,  
  144. status,  
  145. dw_start_date,  
  146. dw_end_date  
  147. FROM (  
  148.     SELECT a.orderid,  
  149.     a.createtime,  
  150.     a.modifiedtime,  
  151.     a.status,  
  152.     a.dw_start_date,  
  153.     CASE WHEN b.orderid IS NOT NULL AND a.dw_end_date > '2016-08-21' THEN '2016-08-21' ELSE a.dw_end_date END AS dw_end_date  
  154.     FROM dw_orders_his a  
  155.     left outer join (SELECT * FROM ods_orders_inc WHERE day = '2016-08-21') b  
  156.     ON (a.orderid = b.orderid)  
  157.     UNION ALL  
  158.     SELECT orderid,  
  159.     createtime,  
  160.     modifiedtime,  
  161.     status,  
  162.     modifiedtime AS dw_start_date,  
  163.     '9999-12-31' AS dw_end_date  
  164.     FROM ods_orders_inc  
  165.     WHERE day = '2016-08-21'  
  166. ) x  
  167. ORDER BY orderid,dw_start_date;  
  168.    
  169. INSERT overwrite TABLE dw_orders_his  
  170. SELECT * FROM dw_orders_his_tmp;  
  171. 在根据上面步骤把2016-08-22号的数据更新进去,最后结果如下  
  172.   
  173.    
  174. select * from dw_orders_his;  
  175. OK  
  176. 1  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  177. 1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21  
  178. 1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31  
  179. 2  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  180. 2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31  
  181. 3  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-21  
  182. 3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31  
  183. 4  2016-08-21  2016-08-21  创建 2016-08-21  2016-08-21  
  184. 4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31  
  185. 5  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31  
  186. 至此,就得到了我们想要的数据。  

 

值得注意的是,订单表中数据同一天有多次状态更新,应以每天的最后一个状态为当天的最终状态。比如一天之内订单状态创建,支付,完成都有,应拉取最终的状态进行拉练表更新,否则后面的数据可能就会出现异常,比如

 

[sql] view plain copy
 
  1. 6  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31  
  2. 6  2016-08-22  2016-08-22  支付 2016-08-22  9999-12-31  
  3. 6  2016-08-22  2016-08-22  完成 2016-08-22  9999-12-31  


http://www.cnblogs.com/wujin/p/6121754.html

http://www.jianshu.com/p/799252156379

http://lxw1234.com/archives/2015/04/20.htm
版权声明:本文为博主原创文章,未经博主允许随机转载。 https://blog.csdn.net/mtj66/article/details/78019370

 

posted @ 2018-06-23 15:50  王振龙  阅读(726)  评论(0编辑  收藏  举报
Live2D