拉鍊表
和流水錶
都是爲了記錄數據的歷史信息。
只是數據粒度的不同。
流水錶精確到每天的每一條變化都記錄其歷史。而拉鍊表的粒度可控,一般選擇每天爲粒度,即每天的最終變化才記錄。
所以理解了拉鍊表,自然就知道流水錶了。
下面通過一個例子理解一下拉鍊表
2019-9-10
用戶id | 金額 | 時間 |
---|---|---|
001 | 500 | 2019-9-10 12:00:00 |
002 | 600 | 2019-9-10 7:00:00 |
003 | 700 | 2019-9-10 16:00:00 |
此時的拉鍊表
用戶id | 金額 | 時間 | 到期時間 |
---|---|---|---|
001 | 500 | 2019-9-10 12:00:00 | 9999-99-99 99:99:99 |
002 | 600 | 2019-9-10 7:00:00 | 9999-99-99 99:99:99 |
003 | 700 | 2019-9-10 16:00:00 | 9999-99-99 99:99:99 |
這裏的到期日期只是一個標誌,用來標記這個數據是當前的數據還是歷史數據。
9999-99-99 99:99:99 這個時間是可以自定義的。甚至不用時間用任意自定義的標識符都行。
2019-9-11
用戶id | 金額 | 時間 |
---|---|---|
001 | 500 | 2019-9-11 12:00:00 |
002 | 200 | 2019-9-11 17:00:00 |
003 | 800 | 2019-9-11 10:00:00 |
變更記錄
用戶id | 金額 | 時間 | 備註 |
---|---|---|---|
002 | 400 | 2019-9-11 10:00:00 | 取款200 |
003 | 800 | 2019-9-11 10:00:00 | 存款100 |
002 | 200 | 2019-9-11 17:00:00 | 取款200 |
此時的拉鍊表
用戶id | 金額 | 時間 | 到期時間 |
---|---|---|---|
001 | 500 | 2019-9-10 12:00:00 | 9999-99-99 99:99:99 |
002 | 600 | 2019-9-10 7:00:00 | 2019-9-11 17:00:00 |
002 | 200 | 2019-9-11 17:00:00 | 9999-99-99 99:99:99 |
003 | 700 | 2019-9-10 16:00:00 | 2019-9-11 10:00:00 |
003 | 800 | 2019-9-11 10:00:00 | 9999-99-99 99:99:99 |
可以看到,9-11號這天,002號用戶有兩條交易記錄,最後也只記錄了當天
最終的變化一條記錄。這就是以天爲粒度的拉鍊表。如果有很多天都變化,拉鍊表中就會有多條記錄。
如何得到拉鍊表?
我們可以通過Cannl監聽mysql的數據變化,然後每天做一個合併,再同步到hdfs上。
提一下,變更記錄
一般是在mysql端處理(合併)的。所以到了ods層,每個用戶的變更記錄已經只有一條了。
表結構
-- 用戶賬戶表
create table if not exists zzy.account_info(
id string,
money int,
in_time string -- 進賬時間
)
row format delimited fields terminated by ' ';
-- 賬戶變更表
create table if not exists zzy.account_change_detail(
id string,
money int,
in_time string, -- 交易時間
`comment` string -- 交易細節
)
row format delimited fields terminated by ' ';
-- 賬戶拉鍊表
create table if not exists zzy.account_zipper(
id string,
money int,
in_time string, -- 進賬時間
out_time string -- 這條記錄過期時間
)
row format delimited fields terminated by ' ';
更新拉鍊表
insert overwrite table zzy.account_zipper
select -- 更新這才變更的記錄
a.id,
a.money,
a.in_time,
(
case
when out_time="9999-99-99 99:99:99" and b.id is not null
then b.in_time
else out_time --如果沒匹配上說明是歷史記錄 原樣保留就行
end
) out_time
from zzy.account_zipper a
left join zzy.account_change_detail b
on a.id=b.id
union
select -- 追加新記錄
id,
money,
in_time,
'9999-99-99 99:99:99' out_time
from zzy.account_change_detail