HIVE開發總結



 

基本數據類型

說明: D:\WizNote\temp\29bda748-a828-45fc-8a5c-5b74d0497a11.png

說明: D:\WizNote\temp\fe2eb873-d708-486f-9e04-f26237726af9.png

(常用的兩種建表例子)

查看所有函數

SHOW FUNCTIONS;

搜索函數

[erp@master2-dev ~]$ hive -S -e "SHOW FUNCTIONS" | grep time

from_unixtime

from_utc_timestamp

to_unix_timestamp

to_utc_timestamp

unix_timestamp

 

[erp@master2-dev ~]$ hive -S -e "SHOW FUNCTIONS" | grep date

date_add

date_sub

datediff

finance.getdate

to_date

搜索表

SHOW TABLES;

SHOW TABLES '*534';

查看函數使用方法

DESCRIBE FUNCTION EXTENDED concat;

關鍵字補全

命令行中的Tab:列出所有關鍵字及補全。所以如果腳本需要在HIVE命令行里直接調試時,腳本不要使用Tab來縮進,使用空格

顯示表頭

set hive.cli.print.header=true;

SET環境變量

說明: D:\WizNote\temp\e2db1e6d-104e-4b0a-bfdd-75e23fb18a39.png

在命令行中,可以使用 SET 命令顯示或者修改變量的值

如果直接輸入 SET  命令,即會顯示所有環境變量

hivevar hiveconf 變量不同的是,system: env: 前綴是不能省略的

使用變量:${變量}

set hivevar:dd=aa;  

select '${hivevar:dd}';//注:使用時加上命名空間

注:定義與使用時還是最好加上hivevar名稱空間,否則可能找不到

set hiveconf:hive.exec.dynamic.partition.mode=nonstrict;

查看建表語句、數據文件置

show create table sap_r3_zfit534;

DESCRIBE formatted  sap_r3_zfit534;

執行外部命令

hive命令提示符下執行Hadoopdfs命令:

只需要將hadoop命令中的關鍵字hadoop去掉,並以分號結尾即可:

dfs -ls hdfs://SuningHadoop2/user/erp/hive/warehouse/erp.db/ztst_6;

 

用戶在不用退出hive命令符就可以執行簡單的 bash shell 命令:以 ! 開頭,以 ; 結尾

hive> ! echo 'Hello';

NVL

NVL( string1, replace_with)  

string1 NULLNVL函數返replace_with值,否則返string1

droptable test;

CREATETABLE test AS

SELECT'a' f1,nullas f2,1 as f3 

unionall

SELECT'b' f1,'c'as f2,1 as f3;

select *,nvl(f2,'值為NULL') from test;

CONCAT

concat(str1, str2, ... strN):如果其中任何一個為NULL,則結果為NULL,所以最好結合NVL使用:

concat(NVL(a.office,''),'00',NVL(b.posOrderId,'')))

droptable test;

CREATETABLE test AS

SELECT'a' f1,nullas f2,1 as f3 

unionall

SELECT'b' f1,'c'as f2,1 as f3;

select *,concat(f1,f2,f3) from test;         

select *,concat(f1,nvl(f2,'NULL'),f3) from test;

IF

if(條件,1,2)

當條件為真時,取值1,否則取值2。值1或值2還可以是其他可返回值的函數表達式,如IFCASE,即可以嵌套IF

droptable test;

CREATETABLE test AS

SELECT'a' f1,nullas f2,1 as f3 

unionall

SELECT'b' f1,'c'as f2,1 as f3;

select *,if(f2 isnull,'NULL','NOT NULL') from test;

CASE

情況很多時,可以使用CASE來代替嵌套的IF

case

    when b.kunnr is not null and b.kunnr <> '' then b.kunnr

    when b.lifnr is not null and b.lifnr <> '' then b.lifnr

    else b.hkont

end

 

droptable test;

CREATETABLE test AS

SELECT'a' f1,nullas f2,1 as f3 

unionall

SELECT'b' f1,'c'as f2,2 as f3

unionall

SELECT'c' f1,'d'as f2,3 as f3;

select *,case f3 when 1 then'' when 2 then'' when 3 then''endfrom test;

TRIM

去除前后空格

selecttrim('   facebook  '),length(trim('   facebook  '));

如果為NULL,則trim結果還是NULL

droptable test;

CREATETABLE test AS

SELECT'a' f1,nullas f2,1 as f3

unionall

SELECT'b' f1,'c'as f2,2 as f3;

select *,trim(f2) from test;

注:Trim不能直接對NULL進行操作:

hive> selecttrim(null); 

FAILED: SemanticException [Error 10014]: Line 1:7 Wrong arguments 'TOK_NULL': trim takes only STRING/CHAR/VARCHAR types. Found VOID

但通過其他函數返回的NULL值是可以的(因為這些函數返回的類型為字符類型而非VOID類型):

selecttrim(if(1<>1,'1',null));

SUBSTRING

substr(str, pos[, len]) :位置是從1開始數,不是0。如果是負,則從后往前數,然后再截后面

SELECTsubstr('Facebook', 5) ;

'book'

SELECTsubstr('Facebook', -5) ;

'ebook'

SELECTsubstr('Facebook', 5, 1);;

'b'

substring(a.XBLNR,1,4)--XBLNR前四位

如果為NULL,則返回NULL

LENGTH

字符串長度

如果為NULL,則返回NULL

注:NULL <> 0

UPPER

轉大寫:

upper(trim(nvl(c.USNAM,''))) <> 'RETAIL'

如果為NULL,則返回NULL

非空判斷

如果有將NULL與空字符串都看做空的話,可以這樣:

trim(nvl(b.KUNNR,'')) <> ''

LPAD

左填充:lpad(str, len, pad)

如果str長度小於len,則使用pad填充左側直到len長度:

SELECTlpad('hi', 5, '??') ;

如果str長度大於len,則會截斷至len長度:

SELECTlpad('hi', 1, '??') ;

rpad(str, len, pad)

日期函數

select from_unixtime(unix_timestamp(),'yyyy-MM-dd HH:mm:ss'); --當前時間

select from_unixtime(unix_timestamp('20150101','yyyyMMdd'),'yyy-MM-dd'); --格式化

select from_unixtime(unix_timestamp('2015/01-01','yyyy/MM-dd'),'yyyMMdd');--去掉日期格式

unix_timestamp('20150101','yyyyMMdd') to_unix_timestamp('20150101','yyyyMMdd')相同

unix_timestamp 可以返回當前時間to_unix_timestamp不可以

is null = = null】?、【is not null = <> null】?

hive 里(包括IF函數與Where條件里)判斷是否為NULL要用 is null is not null ,不能使用 <> null = null(雖然不報錯)

測試如下:

droptable test;

CREATETABLE test AS

SELECT'a' f1,nullas f2,1 as f3 

unionall

SELECT'b' f1,'c'as f2,1 as f3;

select * from test where f2 = null;

select * from test where f2 isnull;

select *,if(f2=null,'null','not null') from test;

select *,if(f2 isnull,'null','not null') from test;

 [NOT] IN[NOT] EXISTSLEFT SEMI JOIN

droptable test1;

CREATETABLE test1 AS

SELECT'a' f1,nullas f2,1 as f3 

unionall

SELECT'b' f1,'c'as f2,2 as f3;

 

droptable test2;

CREATETABLE test2 AS

SELECT'a' f1,nullas f2,3 as f3 

unionall

SELECT'd' f1,'d'as f2,4 as f3;

select * from test1 a whereEXISTS(select f1 from test2 b where a.f1 = b.f1); --注:HIVE與標准SQL不同的是:[NOT] EXISTS后面跟的子查詢一定要是相關子查詢,否則運行出錯(相關子查詢對外層查詢結果集中的每條記錄都會執行一次,所以盡量少用相關子查詢——標准SQL好似這樣,HIVE不一定)

select * from test1 a where a.f1 IN(select f1 from test2 b);

select * from test1 a  LEFT SEMI JOIN test2 b on a.f1 = b.f1;

SEMI-JOIN比通常的inner JION效率要高:對於左表中的一條記錄,在右邊表中一旦找到匹配的記錄,Hive就會立即停止掃描

LEFT SEMI JOIN 的限制是:右表中的字段只能在ON 子句中設置過濾條件,在 WHERE 子句、SELECT 子句或其他地方過濾都不行,所以這也就是為什么LEFT SEMI JOIN 只能當作 IN/EXISTS 來使用的原因

早期版本可能還不支持[NOT] IN[NOT] EXISTS,所以最好使用LEFT SEMI JOIN

ORDER BYSORT BY

ORDER BY為全局排序,會將所有數據送到同一個Reducer中后再對所有數據進行排序,對於大數據會很慢,謹慎使用

SORT BY為局部排序,只會在每一個Reducer中對數據進行排序,在每個Reducer輸出是有序的,但並非全局排序(每個reducer出來的數據是有序的,但是不能保證所有的數據是有序的——即文件(分區)之間無序,除非只有一個reducer

DISTRIBUTE BY 是控制map的輸出被送到哪個reducer端進行匯總計算。注:HIVE reducer分區個數由mapreduce.job.reduces來決定,該選項只決定使用哪些字段做為分區依據,如果沒通過DISTRIBUTE BY指定分區字段,則默認將整個文本行做為分區依據。分區算法默認是HASH,也可以自己實現。

:這里DISTRIBUTE BY講的分區概念是指Hadoop里的,而非我們HIVE數據文本存儲分區。Hadoop里的Partition主要作用就是將map的結果發送到相應的reduce,默認使用HASH算法,不過可以重寫

droptable test1;

createtable test1 as

select'typea' f1,6 f2

unionall

select'typea' f1,2 f2

unionall

select'typeb' f1,7 f2

unionall

select'typec' f1,8 f2

unionall

select'typeb' f1,5 f2

unionall

select'typea' f1,1 f2

unionall

select'typeb' f1,3 f2

unionall

select'typec' f1,4 f2;

select * from test1 orderby f2 asc;--全局有序

set mapreduce.job.reduces=10;

select * from test1 sort by f2;--雖然SORT BY是區內有序,但由於未通過DISTRIBUTE指定分區字段,而最大分區又設置為了10,所以每條記錄所分配到的reducer可能不盡相同(有可能某兩條會放在同一分區中,這取決於HASH算法),所以此時看不出什么區內有序

set mapreduce.job.reduces=1;

select * from test1 sort by f2;--將最大分區設置為一個分區,所以具有order by一樣具有全局排序效果

set mapreduce.job.reduces=10;

select * from test1 DISTRIBUTE BY f1 sort by f2;--將最大分區設為10,再通過DISTRIBUTE指定分區字段,而不使用默認整行文本來分區

set mapreduce.job.reduces=2;

select * from test1 DISTRIBUTE BY f1 sort by f2;--由於分區最大設置為2f1分區字段值有3種,這會根據HASH分區算法,會將其中某兩種放在同一分區,而另外一種放在另外的分區,最終看到兩個分區內部也是有序的

ROW_NUMBER

類似Oracle中的ROWNUM,給查詢出的記錄編號,HIVE中一般與DISTRIBUTE BY一起使用。其作用按指定的列進行分組生成行序列,在ROW_NUMBER() 時,會根據 DISTRIBUTE BY (a,b...)中指定的列來判斷,若兩條記錄的ab列相同,則行序列+1,否則重新計數。因為HIVE是基於MAPREADUCE的,必須保證列值相同的記錄要在同一個reduce,所以需要與DISTRIBUTE BY結合使用,否則ROW_NUMBER無意義。

假設一個場景:存在表test1,該表的數據如下

id    rate      score

1     '0-4'      10

2     '0-4'      40

3     '0-4'      30

4     '0-4'      20

5     '5-10'   10

6     '5-10'   40

7     '5-10'   30

8     '5-10'   20

9     '11-20' 10

10  '11-20' 40

11  '11-20' 30

12  '11-20' 20

現在要求用一條查詢語句取出每種ratescore最大的兩條記錄,也就算取出id為:23671011的記錄

droptable test1;

createtable test1 as

select 1 id,'0-4' rate,10 score

unionall

select 2 id,'0-4' rate,40 score

unionall

select 3 id,'0-4' rate,30 score

unionall

select 4 id,'0-4' rate,20 score

unionall

select 5 id,'5-10' rate,10 score

unionall

select 6 id,'5-10' rate,40 score

unionall

select 7 id,'5-10' rate,30 score

unionall

select 8 id,'5-10' rate,20 score

unionall

select 9 id,'11-20' rate,10 score

unionall

select 10 id,'11-20' rate,40 score

unionall

select 11 id,'11-20' rate,30 score

unionall

select 12 id,'11-20' rate,20 score;

 

SELECT a.*  FROM(SELECT *,row_number() over (distribute by rate SORTBY rate ASC, score DESC) rownum FROM test1 )  a WHERE rownum  <= 2 ;--結果正確,只啟動一個JOB

注:可以去掉SORT BY后面分區字段,而不影響結果,應該是在排序時默認就已加上了分區字段,但以防出錯,不要省略

注:ROW_NUMBER+DISTRIBUTE BY結果與分區個數無關,所以通過set mapreduce.job.reduces不會影響正確結果:

hive> set mapreduce.job.reduces=1;

hive> SELECT a.*  FROM(SELECT *,row_number() over (distribute by rate SORT BY score DESC) rownum FROM test1 )  a WHERE rownum  <= 20;

 

SELECT a.*  FROM(SELECT *,row_number() over (partition  by rate ) rownum  FROM test1 SORT BY rate ASC, score DESC)  a WHERE rownum  <= 2 ;--看見有人這么用過,但結果不正確partition到底有啥用?會啟動兩個JOB,相對於distribute感覺慢,所以還是使用distribute

row_number()另一作用可以用來去除重復:先按分組字段分區,再通過 rownum = 1過濾即可。另外,去重還可以借助於group by

select actual_pymnt_dt from sap_r3_ZFIT684_tmp groupby actual_pymnt_dt

ON > WHERE > HAVING

為了提交性能,INNER JOIN時,非連接條件放置的位置應該按照 ON > WHERE > HAVING的順序優先放置,因為SQL條件的的執行一般是按這個順序來執行的,將條件放在最開始執行,則可過濾掉大部數據;

如果是LEFT JOIN,非連接條件放在WHERE還是ON中是有所不同的,請參考后面

ON非連接字段條件問題

1、          ON條件中不支持OR連接,只能使用AND

2、          在外連接中,不要輕易的將Where中的條件移到ON連接語句中(雖然不報錯),因為在HIVE的外連接ON語句中,會忽略(嚴格來講不是忽略,而是只拿滿足條件的記錄去與另一表進行關聯,左表沒關聯上的還是會顯示出來,請看后面實驗)掉所有除連接字段條件所有條件

droptable test1;

CREATETABLE test1 AS

SELECT'a' f1,nullas f2,1 as f3 

unionall

SELECT'b' f1,'c'as f2,2 as f3;

 

droptable test2;

CREATETABLE test2 AS

SELECT'a' f1,nullas f2,3 as f3 

unionall

SELECT'd' f1,'d'as f2,4 as f3;

select * from test1 a leftjoin test2 b on a.f1=b.f1;

select * from test1 a leftjoin test2 b on a.f1=b.f1 and a.f1='a';

select * from test1 a leftjoin test2 b on a.f1=b.f1 where a.f1='a';

嚴格為講,ON中的非連接條件還是起一定作用的:如下面的a記錄所對應的右表記錄為NULL,因為條件a.f1='b'只會拿滿足條件的左表記錄b去與右表去關聯,但未關聯上,所以對應的右表顯示為NULL;不滿足條件的左表記錄a不會去做關聯(雖然在右表中存在),但還是會顯示出來,只是所以對應的右表也顯示為NULL

select * from test1 a leftjoin test2 b on a.f1 = b.f1 and a.f1 = 'b';

思考下面的結果?

select * from test1 a leftjoin test2 b on a.f1=b.f1 and b.f1='d';

 

對於INNER JOINON語中中的非連接條件是起做用的:

select * from test1 a innerjoin test2 b on a.f1=b.f1 and a.f1='a';

總結

1、          如果是INNER JOIN,為了提高性能,非連接字段條件最好放置在ON從句中

2、    如果是LEFT JOIN,非連接字段條件最好放在Where從句中,但若想放在ON從句中,可以使用嵌套子查詢來解決不必要的麻煩:

在外聯連中,如果要想Where語句中的條件移到ON語句中,可以使用如下的嵌套語句來實現,這樣即在聯接前過濾了不必要的數據,提高效率的同時又沒有丟掉數據:

select * from (select * from test1 where f1='a') a leftjoin test2 b on a.f1=b.f1;

NULL值條件問題

如果某字段存為NULL的值,則用該字段進行過濾時,NULL需要單獨處理:

droptable test1;

CREATETABLE test1 AS

SELECT'a' f1,nullas f2,1 as f3 

unionall

SELECT'b' f1,'c'as f2,2 as f3

unionall

SELECT'd' f1,'d'as f2,3 as f3;

select * from test1 where f2 <> 'c';--NULL值的沒有查出來(標准SQL也是這樣的)

select * from test1 where f2 <> 'c' or f2 is null; --如果需要取出NULL,需要單獨加上

正則表達式

regexp_extract(str, regexp[, idx]) - extracts a group that matches regexp抽取匹配到的指定組

SELECT regexp_extract('100\\200', '^(\\d+).(\\d+)$', 0);

100\200

 

SELECT regexp_extract('100-200', '^([0-9]+)-([0-9]+)$', 1);

100

 

SELECT regexp_extract('100-200', '^([0-9]+)-(\\d+)$', 2);

200

注:\需要使用轉義一下

小數精度問題

不要使用Float類型

在建表時,如果要將金額字段定義成數據類型,請將定義成Double類型,或對數字類型比較時,請先轉換成Double再進行比較,否則不准確(早其版本會有精度丟失問題):

cast(a.payAmount as double) = cast(b.payAmount as double)

或者直接通過字符串比較的方式來比較數字,但比較前需要前后對齊(如不補齊會導致9.8 > 10.8),請看下面:

select a as a000000000,

regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',0) c0,--整個匹配

regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',1) c1,--正負號

regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',2) c2,--整數部分

regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',3) c3,--小數點

regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',4) c4,--小數部分

case concat(regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',1),'')

when '-'then

concat('-',lpad(regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',2),16,'0'),'.',

rpad(regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',4),4,'0'))

else

concat('0',lpad(regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',2),16,'0'),'.',

rpad(regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',4),4,'0'))

end c500000000000000000000,--整數、小數部分對齊

case concat(regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',1),'')

when '-'then

cast(concat('-',lpad(regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',2),16,'0'),'.',

rpad(regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',4),4,'0')) asdouble)

else

cast(concat('0',lpad(regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',2),16,'0'),'.',

rpad(regexp_extract(trim(a),'^([-+]?)([0-9]*)(\.?)([0-9]*)$',4),4,'0')) asdouble)

end c6--轉換成真正的小數

from test0002;

增量更新表

insert overwrite table erp.tsor_BKPF --要更新此表

SELECT td.* FROM (

              select  ta.*

              from erp.tsor_BKPF ta  --先要把原來中未更新的數據撈出來

              leftjoin (select tc.MANDT,tc.BUKRS,tc.BELNR,tc.GJAHR from BI_SOR.TSOR_FN_R3_BKPF_D tc --此表為增量表

              where tc.STATIS_DATE='${hivevar:statis_date}' )tb on

                         ta.MANDT=tb.MANDT

                     and ta.BUKRS=tb.BUKRS

                        and ta.BELNR=tb.BELNR

                     and ta.GJAHR=tb.GJAHR

              where concat(tb.MANDT,tb.BUKRS,tb.BELNR,tb.GJAHR) isnull

 

union all

 

              select  ta.*      --再與發生更新的數據Union

              from BI_SOR.TSOR_FN_R3_BKPF_D ta

              where ta.STATIS_DATE='${hivevar:statis_date}'

)td;

 

分區表更新:

insert overwrite table erp.sap_r3_ZFIT684 PARTITION (actual_pymnt_dt)

select e.* from

(

       --未更新的數據

       select a.* from (

       select * from erp.sap_r3_ZFIT684 d  --目標表

       --CBT平台拋數據任務里不支持 HIVE變量,所以如果要使用 ${hivevar:statis_date}變量的話,需要將后置SQL做成HIVE任務

       --where actual_pymnt_dt = '${hivevar:statis_date}'

       LEFT SEMI JOIN (select actual_pymnt_dt from sap_r3_ZFIT684_tmp groupby actual_pymnt_dt) dd

       ond.actual_pymnt_dt = dd.actual_pymnt_dt--從目標表中只撈出需要處理的分區數據

       ) a

       leftjoin (select

       mandt,serial_no,shkzg,xblnr,payee_co_code,biz_categ,biz_sub_categ,zuonr,money,pymnt_amt,

       supplier_name,waers,twaers,sgtxt,bukrs3,belnr3,gjahr3,flag3,meg3,belnr2,gjahr2,flag2,meg2,

belnr1,gjahr1,budat1,flag1,meg1,msg,clear,refund_no,file_name,RECIVE_DT,RECIVE_TM,actual_pymnt_dt

       from  erp.sap_r3_ZFIT684_tmp) b  --增量表

       on a.MANDT=b.MANDT and a.SERIAL_NO=b.SERIAL_NO and a.SHKZG=b.SHKZG --通過主鍵進行關聯

       where b.MANDT isnulland b.SERIAL_NO isnulland b.SHKZG isnull

 

union all

 

       --已更新的數據(包括新增、修改的數據,刪除需要在上面取未更新的數據時過濾掉即可 )

       select

       mandt,serial_no,shkzg,xblnr,payee_co_code,biz_categ,biz_sub_categ,zuonr,money,pymnt_amt,

       supplier_name,waers,twaers,sgtxt,bukrs3,belnr3,gjahr3,flag3,meg3,belnr2,gjahr2,flag2,meg2,

belnr1,gjahr1,budat1,flag1,meg1,msg,clear,refund_no,file_name,RECIVE_DT,RECIVE_TM,actual_pymnt_dt

       from erp.sap_r3_ZFIT684_tmp c

) e;

其他

1、              JOIN查詢時,盡量將小表放在前面

2、              兩個表join的時候,不支持兩個表的字段非等值操作,可以將非相等條件提取到where

附件列表

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM