源表和目標表,比對的時候,某部分數據,每次比對都被認爲是“新數據”,然後每次抽取比對都會被過濾到目標表,從而造成目標表有很多重複數據,是什麼原因呢?原因是該表的多個字段“數據缺失嚴重”,我們比對數據前是已經給空值/空格填了默認值,也就是說這些被填充過的字段,是有很多重複值的。我們聯表查詢時,關聯字段時有重複值時,那這次查詢肯定會發散,而我們用的kettle【合併記錄】插件的原理也是聯表查詢。
我的上一篇文章《ODS層更新:如果源數據沒有“更新時間“字段,如何作增量抽取?我都踩過這些坑》提到用來聯表的字段,一定是該條的數據的唯一標識。如果不是的話,那就造一個,多個字段作爲“關聯字段”避免發散。如果一條數據,10個字段,7個字段缺失,你怎麼造“唯一標識”,最後聯表比對時,還是會發散。也就是說,聯表時,某部分數據字段值缺失嚴重,多對多聯表是有風險的,那有沒有其他取增量更優的解決方案呢?
即然多對多聯表有風險,那就一對一聯表,不就解決了嗎?
- 取增量思路:源表 left outer join 目標表
源表
LEFT OUTER JOIN
目標表
WHERE 目標表.關聯字段 IS NULL - 建【源表】
CREATE TABLE work_exper(
id NUMBER(10),
name VARCHAR2(10),
company VARCHAR2(10),
job VARCHAR2(10),
work_start_date date,
work_end_date date
);
- 給【源表】插入數據
INSERT INTO work_exper VALUES(1001,'喪彪','百度','清潔工',to_date('1997-05-17','yyyy-mm-dd'),to_date('1998-08-15','yyyy-mm-dd'));
INSERT INTO work_exper VALUES(1001,'喪彪','騰訊','保安',to_date('1998-09-17','yyyy-mm-dd'),to_date('1999-12-15','yyyy-mm-dd'));
INSERT INTO work_exper VALUES(1001,'喪彪','阿里','炊事員',to_date('2000-07-17','yyyy-mm-dd'),to_date('2002-03-18','yyyy-mm-dd'));
INSERT INTO work_exper VALUES(1002,'段坤','快手','運營專員',to_date('1996-08-27','yyyy-mm-dd'),to_date('1998-02-08','yyyy-mm-dd'));
INSERT INTO work_exper VALUES(1002,'段坤','抖音','主播',to_date('1997-01-17','yyyy-mm-dd'),to_date('1998-02-14','yyyy-mm-dd'));
INSERT INTO work_exper VALUES(1002,'段坤','愛奇藝','COO',to_date('1999-05-19','yyyy-mm-dd'),to_date('2008-08-15','yyyy-mm-dd'));
INSERT INTO work_exper VALUES(1003,'阿祖','建行','催收員',to_date('2001-05-17','yyyy-mm-dd'),to_date('2018-04-12','yyyy-mm-dd'));
INSERT INTO work_exper VALUES(1001,'喪彪','阿里','炊事班長',to_date('2003-07-17','yyyy-mm-dd'),to_date('2020-03-18','yyyy-mm-dd'));
- 查詢【源表】:
SELECT
id
,name
,job
,work_start_date
,work_end_date
FROM
work_exper
從上面的源表來看,字段ID+NAME+COMPANY+JOB就可以確定爲該行數據的唯一標識了,但這是“多對多聯表”,現實的業務場景,數據可不是那麼規整的,一定是有很多缺失值的,所以我們如何作“一對一聯表”呢?
- 用窗口函數row_number()over()給源數據造一個唯一標識
一個員工只有一個ID,但有多條工作記錄,那我們可以以“ID"進行分組,在組內進行排序,最終將ID+排序結果,這樣便可以得到"唯一標識"
SELECT
id||'_'||row_number()over(partition by id order by company,job,work_start_date,work_end_date) as pk_id
,id
,name
,job
,work_start_date
,work_end_date
FROM
work_exper
接下來建ods層目標表
- 建ods層【目標表】
CREATE TABLE ods_work_exper(
pk_id VARCHAR2(10),
id NUMBER(10),
name VARCHAR2(10),
company VARCHAR2(10),
job VARCHAR2(10),
work_start_date date,
work_end_date date
);
你可以看出,我並沒有給字段pk_id建立“唯一主鍵約束”,也就是說我允許目標中出現重複的ods_pk_id。爲什麼這樣做呢?因爲id分組組內排序是動態的,難免會出現有一天新數據的pk_id 和某條舊數據的pk_id一樣,但其他字段不一樣的。所以我們取增量的腳本可以改進成。
-
取增量思路改進:
源表
LEFT OUTER JOIN
目標表
WHERE 目標表.關聯字段 IS NULL
OR 源表.字段 <>目標表字段.字段 -
腳本實例:
SELECT
A.pk_id
,A.id
,A.name
,A.company
,A.job
,A.work_start_date
,A.work_end_date
FROM
(
SELECT
id||'_'||row_number()over(partition by id order by company,job,work_start_date,work_end_date) as pk_id
, id
, name
, company
, job
, work_start_date
, work_end_date
FROM
work_exper
) A --源表
LEFT OUTER JOIN
ods_work_exper B --目標表
ON A.pk_id = B.pk_id
WHERE B.pk_id IS NULL
OR A.name <> B.name
OR A.company <> B.company
OR A.job <> B.job
OR A.work_start_date <> B.work_start_date
OR A.work_end_date <> B.work_end_date
實際的業務場景中,源表和目標表都是來自不同的數據庫。如果源數據庫沒有賦權的情況下,異構數據聯表查詢是實現不了的。我們可以藉助kettle的【記錄集連接】插件
(流程概覽)
- 1.1 源表:work_exper
- 1.2目標表:ods_work_exper
- 2.記錄集連接
- 3.過濾記錄
- 4.獲取系統信息
- 5.新增數據插入目標表:ods_work_exper