數據倉庫,Hive中使用 不等於 符號進行條件過濾時的坑

最近在建設數據倉庫,處理數據的過程中,經常反覆使用hive的HQL語句,儘管HQL和SQL語言有很多相同之處,但也並不是說HQL就能通用SQL的語法。在使用過程中要尤爲注意。事情經過是這樣的,我在把業務系統數據同步到數倉(數據存儲在Hive)中時,在數據彙總層(DWS),對數據進行彙總處理時,發現有數據丟失的問題,經過排查,發現是在使用 <> 引發的坑。

Hive 中 != 或 <> 致命陷阱

業務場景:把業務數據抽到ODS層(原始數據層)、在DWS層(數據彙總層),對多張多表中的數據進行彙總操作,目的是爲了補全各表的多種維度指標(維表)。

實際操作:因爲是在Hive直接使用HQL語句對多表進行Join的關聯查詢操作,把處理完成的數據寫入到提前建好的表中。跑完SQL以後,對結果數據進行驗證,發現少了數百萬數據,問題極其嚴重(在實際開發過程中,一定要對結果進行多方面的校驗),開始排查問題。

排查問題:首先是對邏輯進行排查。發現邏輯並無錯誤,之後分解HQL,把每個SQL過濾條件單獨拿出來進行驗證,發現問題。 在使用 <> 產生了坑。

問題思考:在數倉建設過程中,因爲工作疏忽,忘記了對ODS原始數據層的數據進行處理。因爲在把ODS原始數據層的數據同步到到DWS數據彙總層時,並沒有經過DWD數據明細層的處理,導致問題出現。

注意:在數倉建設過程,因爲業務數據、或日誌數據、或其他來源的數據。因爲數據往往是很髒亂差的,我們需要對數據進行清洗操作,也就是ETL過程。但是數據倉庫有個指標很重要,就是要把原始數據原封不動的同步到ODS層,在DWD層對數據進行簡單處理。比如補全數據的操作,對NULL或空值進行補值操作。

 

 對!= 或 <>實操驗證

首先,先建一張表,插入數據:

create table if not exists not_eq_temp values(1,22,'小李','男','銷售')(
  id int comment 'id',
  age int comment '年齡',
  name string comment '姓名',
  sex string comment '性別',
  job string comment '工作'
);

insert into table not_eq_temp values(1,22,'小李','男','銷售');
insert into table not_eq_temp values(2,,'小張','男','');
insert into table not_eq_temp values(3,26,'小麗','女','文員');
insert into table not_eq_temp values(4,22,'小花','女','行政');
insert into table not_eq_temp values(5,25,'小王','男','');
insert into table not_eq_temp values(6,24,'小明','男','銷售');

然後,查詢語句:

select id,age,name,sex,job from not_eq_temp where age <> 22 

查詢結果:

|  3| 26|'小麗'|'女'|'文員'|
|  5| 25|'小王'|'男'|  ''|
|  6| 24|'小明'|'男'|'銷售'|

可以看出來,id爲4的這行數據,在查詢過程中丟失了。因爲這行數據,年齡沒有采集到,爲空,在使用<>時,會把爲null值的也過濾掉,這顯然不是我們想要的結果。

 

如何解決使用<>過濾 空值的問題?

方案一

這就需要用到我們前面說的補值操作。在DWD層對缺少或空值的記錄進行補值處理。

具體方式:

select 
    id,
    if(age is null,floor(rand()*100+200),age) AS age,
    name,
    sex,
    job
from
    not_eq_temp

注意:因爲這裏age是整數,我們使用floor(rand()*100+200) 來對age進行補值操作。這樣做的好處是,使用rand()隨機函數,有效避免數據傾斜情況的出現。

加200的目的,是爲了跟正常年齡進行區別。在後續數據使用中,當我們看到200歲(目前來說沒人能活200歲)以上的目標時,就能第一時間知道,這是我們補的值,原始業務數據並沒有採集到年齡。

這只是一種情況,大家可以靈活使用。字段類型是字符串或其他類型時,補充對應類型的值就行。千萬注意不要補同樣的值,最好是隨機數。

 

方案二

如果我們沒有進行DWD層的操作,也就是沒有補值操作。我們在查詢數據的時候,可以使用條件判斷避免出現null值被過濾的情況。

具體方式:

select    id ,age ,name ,sex ,job from not_eq_temp where coalesce(age,1) <> 22

coalesce的用法,相當於if(expr is null,expr1,expr2)。

當然還有其他很多方式,我們可以在工作中,自己嘗試。但是還是建議使用第一種方式,在DWD層對髒數據進行處理,因爲這是建設數據倉庫過程中很嚴格的規範要求。數據倉庫中,一般dwd層就是用來對ods層數據進行簡單處理的,如果不發揮這層的作用,那就有點不合時宜了。

 

使用不等值!= 或<>需要注意

在使用不等值:<>比較或過濾數據時,需要注意以下多種情況。

先來看看<>語法格式:

語法: A <> B

針對所有基本類型,如果表達式A爲NULL,或者表達式B爲NULL,返回NULL;如果表達式A與表達式B不相等,則爲TRUE;否則爲FALSE。

注意:在關係型數據庫中,通常SQL的寫法中不等於也可以這樣寫 != 。但在hive中,當一個string類型和int類型在進行比較的時候會查不出來結果。

數字和數字類型:可以用 != 比較;

帶引號的數字和數字類型:也可以用!= 比較;

帶引號的數字和帶引號數字類型:還可以用 != 比較;

字符串和數字類型:不可以用 != 比較;

字符串和數字類型:不可以用 <> 比較;

總而言之,在使用!= 或 <>比較的時候兩者的字段類型儘量保持一致。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章