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非鏈接字段條件問題

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

二、          在外鏈接中,不要輕易的將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';

總結

一、          若是是INNER JOIN,爲了提升性能,非鏈接字段條件最好放置在ON從句中

二、    若是是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;

其餘

一、              JOIN查詢時,儘可能將小表放在前面

二、              兩個表join的時候,不支持兩個表的字段非等值操做,能夠將非相等條件提取到where

附件列表

相關文章
相關標籤/搜索