Hive Sql 大全
本文基本涵蓋了Hive日常使用的所有SQL,因為SQL太多,所以將SQL進行了如下分類: 一、DDL陳述句(資料定義陳述句):
對資料庫的操作:包含創建、修改資料庫
對資料表的操作:分為內部表及外部表,磁區表和分桶表
二、DQL陳述句(資料查詢陳述句):
單表查詢、關聯查詢
hive函式:包含聚合函式,條件函式,日期函式,字串函式等
行轉列及列轉行:lateral view 與 explode 以及 reflect
視窗函式與分析函式
其他一些視窗函式
文章首發于公眾號【五分鐘學大資料】,大資料領域原創技術號,每周更新大資料技術文及面試真題決議,關注后可領取精心制作大資料面試寶典!
hive的DDL語法
對資料庫的操作
-
創建資料庫:
create database if not exists myhive;
說明:hive的表存放位置模式是由hive-site.xml當中的一個屬性指定的 :hive.metastore.warehouse.dir
創建資料庫并指定hdfs存盤位置 :
create database myhive2 location '/myhive2';
-
修改資料庫:
alter database myhive2 set dbproperties('createtime'='20210329');
說明:可以使用alter database 命令來修改資料庫的一些屬性,但是資料庫的元資料資訊是不可更改的,包括資料庫的名稱以及資料庫所在的位置
-
查看資料庫詳細資訊
查看資料庫基本資訊
hive (myhive)> desc database myhive2;
查看資料庫更多詳細資訊
hive (myhive)> desc database extended myhive2;
-
洗掉資料庫
洗掉一個空資料庫,如果資料庫下面有資料表,那么就會報錯
drop database myhive2;
強制洗掉資料庫,包含資料庫下面的表一起洗掉
drop database myhive cascade;
對資料表的操作
對管理表(內部表)的操作:
-
建內部表:
hive (myhive)> use myhive; -- 使用myhive資料庫
hive (myhive)> create table stu(id int,name string);
hive (myhive)> insert into stu values (1,"zhangsan");
hive (myhive)> insert into stu values (1,"zhangsan"),(2,"lisi"); -- 一次插入多條資料
hive (myhive)> select * from stu;
-
hive建表時候的欄位型別:
| 分類 | 型別 | 描述 | 字面量示例 |
|---|---|---|---|
| 原始型別 | BOOLEAN | true/false | TRUE |
| TINYINT | 1位元組的有符號整數 -128~127 | 1Y | |
| SMALLINT | 2個位元組的有符號整數,-32768~32767 | 1S | |
| INT | 4個位元組的帶符號整數 | 1 | |
| BIGINT | 8位元組帶符號整數 | 1L | |
| FLOAT | 4位元組單精度浮點數1.0 | ||
| DOUBLE | 8位元組雙精度浮點數 | 1.0 | |
| DEICIMAL | 任意精度的帶符號小數 | 1.0 | |
| STRING | 字串,變長 | “a”,’b’ | |
| VARCHAR | 變長字串 | “a”,’b’ | |
| CHAR | 固定長度字串 | “a”,’b’ | |
| BINARY | 位元組陣列 | 無法表示 | |
| TIMESTAMP | 時間戳,毫秒值精度 | 122327493795 | |
| DATE | 日期 | ‘2016-03-29’ | |
| INTERVAL | 時間頻率間隔 | ||
| 復雜型別 | ARRAY | 有序的的同型別的集合 | array(1,2) |
| MAP | key-value,key必須為原始型別,value可以任意型別 | map(‘a’,1,’b’,2) | |
| STRUCT | 欄位集合,型別可以不同 | struct(‘1’,1,1.0), named_stract(‘col1’,’1’,’col2’,1,’clo3’,1.0) | |
| UNION | 在有限取值范圍內的一個值 | create_union(1,’a’,63) |
對decimal型別簡單解釋下:
用法:decimal(11,2) 代表最多有11位數字,其中后2位是小數,整數部分是9位;如果整數部分超過9位,則這個欄位就會變成null;如果小數部分不足2位,則后面用0補齊兩位,如果小數部分超過兩位,則超出部分四舍五入
也可直接寫 decimal,后面不指定位數,默認是 decimal(10,0) 整數10位,沒有小數
-
創建表并指定欄位之間的分隔符
create table if not exists stu2(id int ,name string) row format delimited fields terminated by '\t' stored as textfile location '/user/stu2';
row format delimited fields terminated by '\t' 指定欄位分隔符,默認分隔符為 '\001'
stored as 指定存盤格式
location 指定存盤位置
-
根據查詢結果創建表
create table stu3 as select * from stu2;
-
根據已經存在的表結構創建表
create table stu4 like stu2;
-
查詢表的結構
只查詢表內欄位及屬性
desc stu2;
詳細查詢
desc formatted stu2;
-
查詢創建表的陳述句
show create table stu2;
對外部表操作
外部表因為是指定其他的hdfs路徑的資料加載到表當中來,所以hive表會認為自己不完全獨占這份資料,所以洗掉hive表的時候,資料仍然存放在hdfs當中,不會刪掉,只會洗掉表的元資料
-
構建外部表
create external table student (s_id string,s_name string) row format delimited fields terminated by '\t';
-
從本地檔案系統向表中加載資料
追加操作
load data local inpath '/export/servers/hivedatas/student.csv' into table student;
覆寫操作
load data local inpath '/export/servers/hivedatas/student.csv' overwrite into table student;
-
從hdfs檔案系統向表中加載資料
load data inpath '/hivedatas/techer.csv' into table techer;
加載資料到指定磁區
load data inpath '/hivedatas/techer.csv' into table techer partition(cur_date=20201210);
注意:
1.使用 load data local 表示從本地檔案系統加載,檔案會拷貝到hdfs上
2.使用 load data 表示從hdfs檔案系統加載,檔案會直接移動到hive相關目錄下,注意不是拷貝過去,因為hive認為hdfs檔案已經有3副本了,沒必要再次拷貝了
3.如果表是磁區表,load 時不指定磁區會報錯
4.如果加載相同檔案名的檔案,會被自動重命名
對磁區表的操作
-
創建磁區表的語法
create table score(s_id string, s_score int) partitioned by (month string);
-
創建一個表帶多個磁區
create table score2 (s_id string, s_score int) partitioned by (year string,month string,day string);
注意:
hive表創建的時候可以用 location 指定一個檔案或者檔案夾,當指定檔案夾時,hive會加載檔案夾下的所有檔案,當表中無磁區時,這個檔案夾下不能再有檔案夾,否則報錯
當表是磁區表時,比如 partitioned by (day string), 則這個檔案夾下的每一個檔案夾就是一個磁區,且檔案夾名為 day=20201123 這種格式,然后使用:msck repair table score; 修復表結構,成功之后即可看到資料已經全部加載到表當中去了
-
加載資料到一個磁區的表中
load data local inpath '/export/servers/hivedatas/score.csv' into table score partition (month='201806');
-
加載資料到一個多磁區的表中去
load data local inpath '/export/servers/hivedatas/score.csv' into table score2 partition(year='2018',month='06',day='01');
-
查看磁區
show partitions score;
-
添加一個磁區
alter table score add partition(month='201805');
-
同時添加多個磁區
alter table score add partition(month='201804') partition(month = '201803');
注意:添加磁區之后就可以在hdfs檔案系統當中看到表下面多了一個檔案夾
-
洗掉磁區
alter table score drop partition(month = '201806');
對分桶表操作
將資料按照指定的欄位進行分成多個桶中去,就是按照分桶欄位進行哈希劃分到多個檔案當中去
磁區就是分檔案夾,分桶就是分檔案
分桶優點:
1. 提高join查詢效率
2. 提高抽樣效率
-
開啟hive的捅表功能
set hive.enforce.bucketing=true;
-
設定reduce的個數
set mapreduce.job.reduces=3;
-
創建桶表
create table course (c_id string,c_name string) clustered by(c_id) into 3 buckets;
桶表的資料加載:由于桶表的資料加載通過hdfs dfs -put檔案或者通過load data均不可以,只能通過insert overwrite 進行加載
所以把檔案加載到桶表中,需要先創建普通表,并通過insert overwrite的方式將普通表的資料通過查詢的方式加載到桶表當中去
-
通過insert overwrite給桶表中加載資料
insert overwrite table course select * from course_common cluster by(c_id); -- 最后指定桶欄位
修改表和洗掉表
-
修改表名稱
alter table old_table_name rename to new_table_name;
-
增加/修改列資訊
查詢表結構
desc score5;
添加列
alter table score5 add columns (mycol string, mysco string);
更新列
alter table score5 change column mysco mysconew int;
-
洗掉表操作
drop table score5;
-
清空表操作
truncate table score6;
說明:只能清空管理表,也就是內部表;清空外部表,會產生錯誤
注意:truncate 和 drop:
如果 hdfs 開啟了回收站,drop 洗掉的表資料是可以從回收站恢復的,表結構恢復不了,需要自己重新創建;truncate 清空的表是不進回收站的,所以無法恢復truncate清空的表
所以 truncate 一定慎用,一旦清空將無力回天
向hive表中加載資料
-
直接向磁區表中插入資料
insert into table score partition(month ='201807') values ('001','002','100');
-
通過load方式加載資料
load data local inpath '/export/servers/hivedatas/score.csv' overwrite into table score partition(month='201806');
-
通過查詢方式加載資料
insert overwrite table score2 partition(month = '201806') select s_id,c_id,s_score from score1;
-
查詢陳述句中創建表并加載資料
create table score2 as select * from score1;
-
在創建表是通過location指定加載資料的路徑
create external table score6 (s_id string,c_id string,s_score int) row format delimited fields terminated by ',' location '/myscore';
-
export匯出與import 匯入 hive表資料(內部表操作)
create table techer2 like techer; --依據已有表結構創建表
export table techer to '/export/techer';
import table techer2 from '/export/techer';
hive表中資料匯出
-
insert匯出
將查詢的結果匯出到本地
insert overwrite local directory '/export/servers/exporthive' select * from score;
將查詢的結果格式化匯出到本地
insert overwrite local directory '/export/servers/exporthive' row format delimited fields terminated by '\t' collection items terminated by '#' select * from student;
將查詢的結果匯出到HDFS上(沒有local)
insert overwrite directory '/export/servers/exporthive' row format delimited fields terminated by '\t' collection items terminated by '#' select * from score;
-
Hadoop命令匯出到本地
dfs -get /export/servers/exporthive/000000_0 /export/servers/exporthive/local.txt;
-
hive shell 命令匯出
基本語法:(hive -f/-e 執行陳述句或者腳本 > file)
hive -e "select * from myhive.score;" > /export/servers/exporthive/score.txt
hive -f export.sh > /export/servers/exporthive/score.txt
-
export匯出到HDFS上
export table score to '/export/exporthive/score';
hive的DQL查詢語法
單表查詢
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list [HAVING condition]]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY| ORDER BY col_list]
]
[LIMIT number]
注意:
1、order by 會對輸入做全域排序,因此只有一個reducer,會導致當輸入規模較大時,需要較長的計算時間,
2、sort by不是全域排序,其在資料進入reducer前完成排序,因此,如果用sort by進行排序,并且設定mapred.reduce.tasks>1,則sort by只保證每個reducer的輸出有序,不保證全域有序,
3、distribute by(欄位)根據指定的欄位將資料分到不同的reducer,且分發演算法是hash散列,
4、Cluster by(欄位) 除了具有Distribute by的功能外,還會對該欄位進行排序,
因此,如果分桶和sort欄位是同一個時,此時,cluster by = distribute by + sort by
-
WHERE陳述句
select * from score where s_score < 60;
注意:
小于某個值是不包含null的,如上查詢結果是把 s_score 為 null 的行剔除的
-
GROUP BY 分組
select s_id ,avg(s_score) from score group by s_id;
分組后對資料進行篩選,使用having
select s_id ,avg(s_score) avgscore from score group by s_id having avgscore > 85;
注意:
如果使用 group by 分組,則 select 后面只能寫分組的欄位或者聚合函式
where和having區別:
1 having是在 group by 分完組之后再對資料進行篩選,所以having 要篩選的欄位只能是分組欄位或者聚合函式
2 where 是從資料表中的欄位直接進行的篩選的,所以不能跟在gruop by后面,也不能使用聚合函式
-
join 連接
INNER JOIN 內連接:只有進行連接的兩個表中都存在與連接條件相匹配的資料才會被保留下來
select * from techer t [inner] join course c on t.t_id = c.t_id; -- inner 可省略
LEFT OUTER JOIN 左外連接:左邊所有資料會被回傳,右邊符合條件的被回傳
select * from techer t left join course c on t.t_id = c.t_id; -- outer可省略
RIGHT OUTER JOIN 右外連接:右邊所有資料會被回傳,左邊符合條件的被回傳、
select * from techer t right join course c on t.t_id = c.t_id;
FULL OUTER JOIN 滿外(全外)連接: 將會回傳所有表中符合條件的所有記錄,如果任一表的指定欄位沒有符合條件的值的話,那么就使用NULL值替代,
SELECT * FROM techer t FULL JOIN course c ON t.t_id = c.t_id ;
注:1. hive2版本已經支持不等值連接,就是 join on條件后面可以使用大于小于符號了;并且也支持 join on 條件后跟or (早前版本 on 后只支持 = 和 and,不支持 > < 和 or)
2.如hive執行引擎使用MapReduce,一個join就會啟動一個job,一條sql陳述句中如有多個join,則會啟動多個job
注意:表之間用逗號(,)連接和 inner join 是一樣的
select * from table_a,table_b where table_a.id=table_b.id;
它們的執行效率沒有區別,只是書寫方式不同,用逗號是sql 89標準,join 是sql 92標準,用逗號連接后面過濾條件用 where ,用 join 連接后面過濾條件是 on,
-
order by 排序
全域排序,只會有一個reduce
ASC(ascend): 升序(默認) DESC(descend): 降序
SELECT * FROM student s LEFT JOIN score sco ON s.s_id = sco.s_id ORDER BY sco.s_score DESC;
注意:order by 是全域排序,所以最后只有一個reduce,也就是在一個節點執行,如果資料量太大,就會耗費較長時間
-
sort by 區域排序
每個MapReduce內部進行排序,對全域結果集來說不是排序,
設定reduce個數
set mapreduce.job.reduces=3;
查看設定reduce個數
set mapreduce.job.reduces;
查詢成績按照成績降序排列
select * from score sort by s_score;
將查詢結果匯入到檔案中(按照成績降序排列)
insert overwrite local directory '/export/servers/hivedatas/sort' select * from score sort by s_score;
-
distribute by 磁區排序
distribute by:類似MR中partition,進行磁區,結合sort by使用
設定reduce的個數,將我們對應的s_id劃分到對應的reduce當中去
set mapreduce.job.reduces=7;
通過distribute by 進行資料的磁區
select * from score distribute by s_id sort by s_score;
注意:Hive要求 distribute by 陳述句要寫在 sort by 陳述句之前
-
cluster by
當distribute by和sort by欄位相同時,可以使用cluster by方式.
cluster by除了具有distribute by的功能外還兼具sort by的功能,但是排序只能是正序排序,不能指定排序規則為ASC或者DESC,
以下兩種寫法等價
select * from score cluster by s_id;
select * from score distribute by s_id sort by s_id;
Hive函式
聚合函式
hive支持 count(),max(),min(),sum(),avg() 等常用的聚合函式
注意:
聚合操作時要注意null值
count(*) 包含null值,統計所有行數
count(id) 不包含null值
min 求最小值是不包含null,除非所有值都是null
avg 求平均值也是不包含null
-
非空集合總體變數函式: var_pop
語法: var_pop(col)
回傳值: double
說明: 統計結果集中col非空集合的總體變數(忽略null)
-
非空集合樣本變數函式: var_samp
語法: var_samp (col)
回傳值: double
說明: 統計結果集中col非空集合的樣本變數(忽略null)
-
總體標準偏離函式: stddev_pop
語法: stddev_pop(col)
回傳值: double
說明: 該函式計算總體標準偏離,并回傳總體變數的平方根,其回傳值與VAR_POP函式的平方根相同
-
中位數函式: percentile
語法: percentile(BIGINT col, p)
回傳值: double
說明: 求準確的第pth個百分位數,p必須介于0和1之間,但是col欄位目前只支持整數,不支持浮點數型別
關系運算
支持:等值(=)、不等值(!= 或 <>)、小于(<)、小于等于(<=)、大于(>)、大于等于(>=)
空值判斷(is null)、非空判斷(is not null)
-
LIKE比較: LIKE
語法: A LIKE B
操作型別: strings
描述: 如果字串A或者字串B為NULL,則回傳NULL;如果字串A符合運算式B 的正則語法,則為TRUE;否則為FALSE,B中字符”_”表示任意單個字符,而字符”%”表示任意數量的字符,
-
JAVA的LIKE操作: RLIKE
語法: A RLIKE B
操作型別: strings
描述: 如果字串A或者字串B為NULL,則回傳NULL;如果字串A符合JAVA正則運算式B的正則語法,則為TRUE;否則為FALSE,
-
REGEXP操作: REGEXP
語法: A REGEXP B
操作型別: strings
描述: 功能與RLIKE相同
示例:select 1 from tableName where 'footbar' REGEXP '^f.*r$';
結果:1
數學運算
支持所有數值型別:加(+)、減(-)、乘(*)、除(/)、取余(%)、位與(&)、位或(|)、位異或(^)、位取反(~)
邏輯運算
支持:邏輯與(and)、邏輯或(or)、邏輯非(not)
數值運算
-
取整函式: round
語法: round(double a)
回傳值: BIGINT
說明: 回傳double型別的整數值部分 (遵循四舍五入)
示例:select round(3.1415926) from tableName;
結果:3
-
指定精度取整函式: round
語法: round(double a, int d)
回傳值: DOUBLE
說明: 回傳指定精度d的double型別
hive> select round(3.1415926,4) from tableName;
3.1416
-
向下取整函式: floor
語法: floor(double a)
回傳值: BIGINT
說明: 回傳等于或者小于該double變數的最大的整數
hive> select floor(3.641) from tableName;
3
-
向上取整函式: ceil
語法: ceil(double a)
回傳值: BIGINT
說明: 回傳等于或者大于該double變數的最小的整數
hive> select ceil(3.1415926) from tableName;
4
-
取亂數函式: rand
語法: rand(),rand(int seed)
回傳值: double
說明: 回傳一個0到1范圍內的亂數,如果指定種子seed,則會等到一個穩定的亂數序列
hive> select rand() from tableName; -- 每次執行此陳述句得到的結果都不同
0.5577432776034763
hive> select rand(100) ; -- 只要指定種子,每次執行此陳述句得到的結果一樣的
0.7220096548596434
-
自然指數函式: exp
語法: exp(double a)
回傳值: double
說明: 回傳自然對數e的a次方
hive> select exp(2) ;
7.38905609893065
-
以10為底對數函式: log10
語法: log10(double a)
回傳值: double
說明: 回傳以10為底的a的對數
hive> select log10(100) ;
2.0
此外還有:以2為底對數函式: log2()、對數函式: log()
-
冪運算函式: pow
語法: pow(double a, double p)
回傳值: double
說明: 回傳a的p次冪
hive> select pow(2,4) ;
16.0
-
開平方函式: sqrt
語法: sqrt(double a)
回傳值: double
說明: 回傳a的平方根
hive> select sqrt(16) ;
4.0
-
二進制函式: bin
語法: bin(BIGINT a)
回傳值: string
說明: 回傳a的二進制代碼表示
hive> select bin(7) ;
111
十六進制函式: hex()、將十六進制轉化為字串函式: unhex()
進制轉換函式: conv(bigint num, int from_base, int to_base) 說明: 將數值num從from_base進制轉化到to_base進制
此外還有很多數學函式: 絕對值函式: abs()、正取余函式: pmod()、正弦函式: sin()、反正弦函式: asin()、余弦函式: cos()、反余弦函式: acos()、positive函式: positive()、negative函式: negative()
條件函式
-
If函式: if
語法: if(boolean testCondition, T valueTrue, T valueFalseOrNull)
回傳值: T
說明: 當條件testCondition為TRUE時,回傳valueTrue;否則回傳valueFalseOrNull
hive> select if(1=2,100,200) ;
200
hive> select if(1=1,100,200) ;
100
-
非空查找函式: coalesce
語法: coalesce(T v1, T v2, …)
回傳值: T
說明: 回傳引數中的第一個非空值;如果所有值都為NULL,那么回傳NULL
hive> select coalesce(null,'100','50') ;
100
-
條件判斷函式:case when (兩種寫法,其一)
語法: case when a then b [when c then d]* [else e] end
回傳值: T
說明:如果a為TRUE,則回傳b;如果c為TRUE,則回傳d;否則回傳e
hive> select case when 1=2 then 'tom' when 2=2 then 'mary' else 'tim' end from tableName;
mary
-
條件判斷函式:case when (兩種寫法,其二)
語法: case a when b then c [when d then e]* [else f] end
回傳值: T
說明:如果a等于b,那么回傳c;如果a等于d,那么回傳e;否則回傳f
hive> Select case 100 when 50 then 'tom' when 100 then 'mary' else 'tim' end from tableName;
mary
日期函式
注:以下SQL陳述句中的 from tableName 可去掉,不影響查詢結果
-
-
獲取當前UNIX時間戳函式: unix_timestamp
-
語法: unix_timestamp()
回傳值: bigint
說明: 獲得當前時區的UNIX時間戳
hive> select unix_timestamp() from tableName;
1616906976
-
-
UNIX時間戳轉日期函式: from_unixtime
-
語法: from_unixtime(bigint unixtime[, string format])
回傳值: string
說明: 轉化UNIX時間戳(從1970-01-01 00:00:00 UTC到指定時間的秒數)到當前時區的時間格式
hive> select from_unixtime(1616906976,'yyyyMMdd') from tableName;
20210328
-
-
日期轉UNIX時間戳函式: unix_timestamp
-
語法: unix_timestamp(string date)
回傳值: bigint
說明: 轉換格式為"yyyy-MM-dd HH:mm:ss"的日期到UNIX時間戳,如果轉化失敗,則回傳0,
hive> select unix_timestamp('2021-03-08 14:21:15') from tableName;
1615184475
-
-
指定格式日期轉UNIX時間戳函式: unix_timestamp
-
語法: unix_timestamp(string date, string pattern)
回傳值: bigint
說明: 轉換pattern格式的日期到UNIX時間戳,如果轉化失敗,則回傳0,
hive> select unix_timestamp('2021-03-08 14:21:15','yyyyMMdd HH:mm:ss') from tableName;
1615184475
-
-
日期時間轉日期函式: to_date
-
語法: to_date(string timestamp)
回傳值: string
說明: 回傳日期時間欄位中的日期部分,
hive> select to_date('2021-03-28 14:03:01') from tableName;
2021-03-28
-
-
日期轉年函式: year
-
語法: year(string date)
回傳值: int
說明: 回傳日期中的年,
hive> select year('2021-03-28 10:03:01') from tableName;
2021
hive> select year('2021-03-28') from tableName;
2021
-
-
日期轉月函式: month
-
語法: month (string date)
回傳值: int
說明: 回傳日期中的月份,
hive> select month('2020-12-28 12:03:01') from tableName;
12
hive> select month('2021-03-08') from tableName;
8
-
-
日期轉天函式: day
-
語法: day (string date)
回傳值: int
說明: 回傳日期中的天,
hive> select day('2020-12-08 10:03:01') from tableName;
8
hive> select day('2020-12-24') from tableName;
24
-
-
日期轉小時函式: hour
-
語法: hour (string date)
回傳值: int
說明: 回傳日期中的小時,
hive> select hour('2020-12-08 10:03:01') from tableName;
10
-
-
日期轉分鐘函式: minute
-
語法: minute (string date)
回傳值: int
說明: 回傳日期中的分鐘,
hive> select minute('2020-12-08 10:03:01') from tableName;
3
-
-
日期轉秒函式: second
-
語法: second (string date)
回傳值: int
說明: 回傳日期中的秒,
hive> select second('2020-12-08 10:03:01') from tableName;
1
-
-
日期轉周函式: weekofyear
-
語法: weekofyear (string date)
回傳值: int
說明: 回傳日期在當前的周數,
hive> select weekofyear('2020-12-08 10:03:01') from tableName;
49
-
-
日期比較函式: datediff
-
語法: datediff(string enddate, string startdate)
回傳值: int
說明: 回傳結束日期減去開始日期的天數,
hive> select datediff('2020-12-08','2012-05-09') from tableName;
213
-
-
日期增加函式: date_add
-
語法: date_add(string startdate, int days)
回傳值: string
說明: 回傳開始日期startdate增加days天后的日期,
hive> select date_add('2020-12-08',10) from tableName;
2020-12-18
-
-
日期減少函式: date_sub
-
語法: date_sub (string startdate, int days)
回傳值: string
說明: 回傳開始日期startdate減少days天后的日期,
hive> select date_sub('2020-12-08',10) from tableName;
2020-11-28
字串函式
-
-
字串長度函式:length
-
語法: length(string A)
回傳值: int
說明:回傳字串A的長度
hive> select length('abcedfg') from tableName;
7
-
-
字串反轉函式:reverse
-
語法: reverse(string A)
回傳值: string
說明:回傳字串A的反轉結果
hive> select reverse('abcedfg') from tableName;
gfdecba
-
-
字串連接函式:concat
-
語法: concat(string A, string B…)
回傳值: string
說明:回傳輸入字串連接后的結果,支持任意個輸入字串
hive> select concat('abc','def’,'gh')from tableName;
abcdefgh
-
-
帶分隔符字串連接函式:concat_ws
-
語法: concat_ws(string SEP, string A, string B…)
回傳值: string
說明:回傳輸入字串連接后的結果,SEP表示各個字串間的分隔符
hive> select concat_ws(',','abc','def','gh')from tableName;
abc,def,gh
-
-
字串截取函式:substr,substring
-
語法: substr(string A, int start),substring(string A, int start)
回傳值: string
說明:回傳字串A從start位置到結尾的字串
hive> select substr('abcde',3) from tableName;
cde
hive> select substring('abcde',3) from tableName;
cde
hive> select substr('abcde',-1) from tableName; (和ORACLE相同)
e
-
-
字串截取函式:substr,substring
-
語法: substr(string A, int start, int len),substring(string A, int start, int len)
回傳值: string
說明:回傳字串A從start位置開始,長度為len的字串
hive> select substr('abcde',3,2) from tableName;
cd
hive> select substring('abcde',3,2) from tableName;
cd
hive>select substring('abcde',-2,2) from tableName;
de
-
-
字串轉大寫函式:upper,ucase
-
語法: upper(string A) ucase(string A)
回傳值: string
說明:回傳字串A的大寫格式
hive> select upper('abSEd') from tableName;
ABSED
hive> select ucase('abSEd') from tableName;
ABSED
-
-
字串轉小寫函式:lower,lcase
-
語法: lower(string A) lcase(string A)
回傳值: string
說明:回傳字串A的小寫格式
hive> select lower('abSEd') from tableName;
absed
hive> select lcase('abSEd') from tableName;
absed
-
-
去空格函式:trim
-
語法: trim(string A)
回傳值: string
說明:去除字串兩邊的空格
hive> select trim(' abc ') from tableName;
abc
-
-
左邊去空格函式:ltrim
-
語法: ltrim(string A)
回傳值: string
說明:去除字串左邊的空格
hive> select ltrim(' abc ') from tableName;
abc
-
-
右邊去空格函式:rtrim
-
語法: rtrim(string A)
回傳值: string
說明:去除字串右邊的空格
hive> select rtrim(' abc ') from tableName;
abc
-
-
正則運算式替換函式:regexp_replace
-
語法: regexp_replace(string A, string B, string C)
回傳值: string
說明:將字串A中的符合java正則運算式B的部分替換為C,注意,在有些情況下要使用轉義字符,類似oracle中的regexp_replace函式,
hive> select regexp_replace('foobar', 'oo|ar', '') from tableName;
fb
-
-
正則運算式決議函式:regexp_extract
-
語法: regexp_extract(string subject, string pattern, int index)
回傳值: string
說明:將字串subject按照pattern正則運算式的規則拆分,回傳index指定的字符,
hive> select regexp_extract('foothebar', 'foo(.*?)(bar)', 1) from tableName;
the
hive> select regexp_extract('foothebar', 'foo(.*?)(bar)', 2) from tableName;
bar
hive> select regexp_extract('foothebar', 'foo(.*?)(bar)', 0) from tableName;
foothebar
strong>注意,在有些情況下要使用轉義字符,下面的等號要用雙豎線轉義,這是java正則運算式的規則,
select data_field,
regexp_extract(data_field,'.*?bgStart\\=([^&]+)',1) as aaa,
regexp_extract(data_field,'.*?contentLoaded_headStart\\=([^&]+)',1) as bbb,
regexp_extract(data_field,'.*?AppLoad2Req\\=([^&]+)',1) as ccc
from pt_nginx_loginlog_st
where pt = '2021-03-28' limit 2;
-
-
URL決議函式:parse_url
-
語法: parse_url(string urlString, string partToExtract [, string keyToExtract])
回傳值: string
說明:回傳URL中指定的部分,partToExtract的有效值為:HOST, PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO.
hive> select parse_url
('https://www.tableName.com/path1/p.php?k1=v1&k2=v2#Ref1', 'HOST')
from tableName;
www.tableName.com
hive> select parse_url
('https://www.tableName.com/path1/p.php?k1=v1&k2=v2#Ref1', 'QUERY', 'k1')
from tableName;
v1
-
-
json決議函式:get_json_object
-
語法: get_json_object(string json_string, string path)
回傳值: string
說明:決議json的字串json_string,回傳path指定的內容,如果輸入的json字串無效,那么回傳NULL,
hive> select get_json_object('{"store":{"fruit":\[{"weight":8,"type":"apple"},{"weight":9,"type":"pear"}], "bicycle":{"price":19.95,"color":"red"} },"email":"amy@only_for_json_udf_test.net","owner":"amy"}','$.owner') from tableName;
-
-
空格字串函式:space
-
語法: space(int n)
回傳值: string
說明:回傳長度為n的字串
hive> select space(10) from tableName;
hive> select length(space(10)) from tableName;
10
-
-
重復字串函式:repeat
-
語法: repeat(string str, int n)
回傳值: string
說明:回傳重復n次后的str字串
hive> select repeat('abc',5) from tableName;
abcabcabcabcabc
-
-
首字符ascii函式:ascii
-
語法: ascii(string str)
回傳值: int
說明:回傳字串str第一個字符的ascii碼
hive> select ascii('abcde') from tableName;
97
-
-
左補足函式:lpad
-
語法: lpad(string str, int len, string pad)
回傳值: string
說明:將str進行用pad進行左補足到len位
hive> select lpad('abc',10,'td') from tableName;
tdtdtdtabc
注意:與GP,ORACLE不同,pad 不能默認
-
-
右補足函式:rpad
-
語法: rpad(string str, int len, string pad)
回傳值: string
說明:將str進行用pad進行右補足到len位
hive> select rpad('abc',10,'td') from tableName;
abctdtdtdt
-
-
分割字串函式: split
-
語法: split(string str, string pat)
回傳值: array
說明: 按照pat字串分割str,會回傳分割后的字串陣列
hive> select split('abtcdtef','t') from tableName;
["ab","cd","ef"]
-
-
集合查找函式: find_in_set
-
語法: find_in_set(string str, string strList)
回傳值: int
說明: 回傳str在strlist第一次出現的位置,strlist是用逗號分割的字串,如果沒有找該str字符,則回傳0
hive> select find_in_set('ab','ef,ab,de') from tableName;
2
hive> select find_in_set('at','ef,ab,de') from tableName;
0
復合型別構建操作
-
Map型別構建: map
語法: map (key1, value1, key2, value2, …)
說明:根據輸入的key和value對構建map型別
hive> Create table mapTable as select map('100','tom','200','mary') as t from tableName;
hive> describe mapTable;
t map<string ,string>
hive> select t from tableName;
{"100":"tom","200":"mary"}
-
-
Struct型別構建: struct
-
語法: struct(val1, val2, val3, …)
說明:根據輸入的引數構建結構體struct型別
hive> create table struct_table as select struct('tom','mary','tim') as t from tableName;
hive> describe struct_table;
t struct<col1:string ,col2:string,col3:string>
hive> select t from tableName;
{"col1":"tom","col2":"mary","col3":"tim"}
-
-
array型別構建: array
-
語法: array(val1, val2, …)
說明:根據輸入的引數構建陣列array型別
hive> create table arr_table as select array("tom","mary","tim") as t from tableName;
hive> describe tableName;
t array<string>
hive> select t from tableName;
["tom","mary","tim"]
復雜型別訪問操作
-
-
array型別訪問: A[n]
-
語法: A[n]
操作型別: A為array型別,n為int型別
說明:回傳陣列A中的第n個變數值,陣列的起始下標為0,比如,A是個值為['foo', 'bar']的陣列型別,那么A[0]將回傳'foo',而A[1]將回傳'bar'
hive> create table arr_table2 as select array("tom","mary","tim") as t
from tableName;
hive> select t[0],t[1] from arr_table2;
tom mary tim
-
-
map型別訪問: M[key]
-
語法: M[key]
操作型別: M為map型別,key為map中的key值
說明:回傳map型別M中,key值為指定值的value值,比如,M是值為{'f' -> 'foo', 'b' -> 'bar', 'all' -> 'foobar'}的map型別,那么M['all']將會回傳'foobar'
hive> Create table map_table2 as select map('100','tom','200','mary') as t from tableName;
hive> select t['200'],t['100'] from map_table2;
mary tom
-
-
struct型別訪問: S.x
-
語法: S.x
操作型別: S為struct型別
說明:回傳結構體S中的x欄位,比如,對于結構體struct foobar {int foo, int bar},foobar.foo回傳結構體中的foo欄位
hive> create table str_table2 as select struct('tom','mary','tim') as t from tableName;
hive> describe tableName;
t struct<col1:string ,col2:string,col3:string>
hive> select t.col1,t.col3 from str_table2;
tom tim
復雜型別長度統計函式
-
-
Map型別長度函式: size(Map<k .V>)
-
語法: size(Map<k .V>)
回傳值: int
說明: 回傳map型別的長度
hive> select size(t) from map_table2;
2
-
-
array型別長度函式: size(Array)
-
語法: size(Array<T>)
回傳值: int
說明: 回傳array型別的長度
hive> select size(t) from arr_table2;
4
-
-
型別轉換函式 ***
-
型別轉換函式: cast
語法: cast(expr as <type>)
回傳值: Expected "=" to follow "type"
說明: 回傳轉換后的資料型別
hive> select cast('1' as bigint) from tableName;
1
hive當中的lateral view 與 explode以及reflect和視窗函式
使用explode函式將hive表中的Map和Array欄位資料進行拆分
? lateral view用于和split、explode等UDTF一起使用的,能將一行資料拆分成多行資料,在此基礎上可以對拆分的資料進行聚合,lateral view首先為原始表的每行呼叫UDTF,UDTF會把一行拆分成一行或者多行,lateral view在把結果組合,產生一個支持別名表的虛擬表,
? 其中explode還可以用于將hive一列中復雜的array或者map結構拆分成多行
需求:現在有資料格式如下
zhangsan child1,child2,child3,child4 k1:v1,k2:v2
lisi child5,child6,child7,child8 k3:v3,k4:v4
? 欄位之間使用\t分割,需求將所有的child進行拆開成為一列
+----------+--+
| mychild |
+----------+--+
| child1 |
| child2 |
| child3 |
| child4 |
| child5 |
| child6 |
| child7 |
| child8 |
+----------+--+
? 將map的key和value也進行拆開,成為如下結果
+-----------+-------------+--+
| mymapkey | mymapvalue |
+-----------+-------------+--+
| k1 | v1 |
| k2 | v2 |
| k3 | v3 |
| k4 | v4 |
+-----------+-------------+--+
-
-
創建hive資料庫
-
創建hive資料庫
hive (default)> create database hive_explode;
hive (default)> use hive_explode;
-
-
創建hive表,然后使用explode拆分map和array
-
hive (hive_explode)> create table t3(name string,children array<string>,address Map<string,string>) row format delimited fields terminated by '\t' collection items terminated by ',' map keys terminated by ':' stored as textFile;
-
-
加載資料
-
node03執行以下命令創建表資料檔案
mkdir -p /export/servers/hivedatas/
cd /export/servers/hivedatas/
vim maparray
內容如下:
zhangsan child1,child2,child3,child4 k1:v1,k2:v2
lisi child5,child6,child7,child8 k3:v3,k4:v4
hive表當中加載資料
hive (hive_explode)> load data local inpath '/export/servers/hivedatas/maparray' into table t3;
-
-
使用explode將hive當中資料拆開
-
將array當中的資料拆分開
hive (hive_explode)> SELECT explode(children) AS myChild FROM t3;
將map當中的資料拆分開
hive (hive_explode)> SELECT explode(address) AS (myMapKey, myMapValue) FROM t3;
使用explode拆分json字串
需求: 需求:現在有一些資料格式如下:
a:shandong,b:beijing,c:hebei|1,2,3,4,5,6,7,8,9|[{"source":"7fresh","monthSales":4900,"userCount":1900,"score":"9.9"},{"source":"jd","monthSales":2090,"userCount":78981,"score":"9.8"},{"source":"jdmart","monthSales":6987,"userCount":1600,"score":"9.0"}]
其中欄位與欄位之間的分隔符是 |
我們要決議得到所有的monthSales對應的值為以下這一列(行轉列)
4900
2090
6987
-
-
創建hive表
-
hive (hive_explode)> create table explode_lateral_view
> (`area` string,
> `goods_id` string,
> `sale_info` string)
> ROW FORMAT DELIMITED
> FIELDS TERMINATED BY '|'
> STORED AS textfile;
-
-
準備資料并加載資料
-
準備資料如下
cd /export/servers/hivedatas
vim explode_json
a:shandong,b:beijing,c:hebei|1,2,3,4,5,6,7,8,9|[{"source":"7fresh","monthSales":4900,"userCount":1900,"score":"9.9"},{"source":"jd","monthSales":2090,"userCount":78981,"score":"9.8"},{"source":"jdmart","monthSales":6987,"userCount":1600,"score":"9.0"}]
加載資料到hive表當中去
hive (hive_explode)> load data local inpath '/export/servers/hivedatas/explode_json' overwrite into table explode_lateral_view;
-
-
使用explode拆分Array
-
hive (hive_explode)> select explode(split(goods_id,',')) as goods_id from explode_lateral_view;
-
-
使用explode拆解Map
-
hive (hive_explode)> select explode(split(area,',')) as area from explode_lateral_view;
-
-
拆解json欄位
-
hive (hive_explode)> select explode(split(regexp_replace(regexp_replace(sale_info,'\\[\\{',''),'}]',''),'},\\{')) as sale_info from explode_lateral_view;
然后我們想用get_json_object來獲取key為monthSales的資料:
hive (hive_explode)> select get_json_object(explode(split(regexp_replace(regexp_replace(sale_info,'\\[\\{',''),'}]',''),'},\\{')),'$.monthSales') as sale_info from explode_lateral_view;
然后掛了FAILED: SemanticException [Error 10081]: UDTF's are not supported outside the SELECT clause, nor nested in expressions
UDTF explode不能寫在別的函式內
如果你這么寫,想查兩個欄位,select explode(split(area,',')) as area,good_id from explode_lateral_view;
會報錯FAILED: SemanticException 1:40 Only a single expression in the SELECT clause is supported with UDTF's. Error encountered near token 'good_id'
使用UDTF的時候,只支持一個欄位,這時候就需要LATERAL VIEW出場了
配合LATERAL VIEW使用
? 配合lateral view查詢多個欄位
hive (hive_explode)> select goods_id2,sale_info from explode_lateral_view LATERAL VIEW explode(split(goods_id,','))goods as goods_id2;
其中LATERAL VIEW explode(split(goods_id,','))goods相當于一個虛擬表,與原表explode_lateral_view笛卡爾積關聯
? 也可以多重使用
hive (hive_explode)> select goods_id2,sale_info,area2
from explode_lateral_view
LATERAL VIEW explode(split(goods_id,','))goods as goods_id2
LATERAL VIEW explode(split(area,','))area as area2;也是三個表笛卡爾積的結果
最終,我們可以通過下面的句子,把這個json格式的一行資料,完全轉換成二維表的方式展現
hive (hive_explode)> select get_json_object(concat('{',sale_info_1,'}'),'$.source') as source,get_json_object(concat('{',sale_info_1,'}'),'$.monthSales') as monthSales,get_json_object(concat('{',sale_info_1,'}'),'$.userCount') as monthSales,get_json_object(concat('{',sale_info_1,'}'),'$.score') as monthSales from explode_lateral_view LATERAL VIEW explode(split(regexp_replace(regexp_replace(sale_info,'\\[\\{',''),'}]',''),'},\\{'))sale_info as sale_info_1;
總結:
Lateral View通常和UDTF一起出現,為了解決UDTF不允許在select欄位的問題, Multiple Lateral View可以實作類似笛卡爾乘積, Outer關鍵字可以把不輸出的UDTF的空結果,輸出成NULL,防止丟失資料,
行轉列
相關引數說明:
? CONCAT(string A/col, string B/col…):回傳輸入字串連接后的結果,支持任意個輸入字串;
? CONCAT_WS(separator, str1, str2,...):它是一個特殊形式的 CONCAT(),第一個引數剩余引數間的分隔符,分隔符可以是與剩余引數一樣的字串,如果分隔符是 NULL,回傳值也將為 NULL,這個函式會跳過分隔符引數后的任何 NULL 和空字串,分隔符將被加到被連接的字串之間;
? COLLECT_SET(col):函式只接受基本資料型別,它的主要作用是將某欄位的值進行去重匯總,產生array型別欄位,
資料準備:
| name | constellation | blood_type |
|---|---|---|
| 孫悟空 | 白羊座 | A |
| 老王 | 射手座 | A |
| 宋宋 | 白羊座 | B |
| 豬八戒 | 白羊座 | A |
| 鳳姐 | 射手座 | A |
需求: 把星座和血型一樣的人歸類到一起,結果如下:
射手座,A 老王|鳳姐
白羊座,A 孫悟空|豬八戒
白羊座,B 宋宋
實作步驟:
-
-
創建本地constellation.txt,匯入資料
-
node03服務器執行以下命令創建檔案,注意資料使用\t進行分割
cd /export/servers/hivedatas
vim constellation.txt
資料如下:
孫悟空 白羊座 A
老王 射手座 A
宋宋 白羊座 B
豬八戒 白羊座 A
鳳姐 射手座 A
-
-
創建hive表并匯入資料
-
創建hive表并加載資料
hive (hive_explode)> create table person_info(
name string,
constellation string,
blood_type string)
row format delimited fields terminated by "\t";
加載資料
hive (hive_explode)> load data local inpath '/export/servers/hivedatas/constellation.txt' into table person_info;
-
-
按需求查詢資料
-
hive (hive_explode)> select
t1.base,
concat_ws('|', collect_set(t1.name)) name
from
(select
name,
concat(constellation, "," , blood_type) base
from
person_info) t1
group by
t1.base;
列轉行
所需函式:
? EXPLODE(col):將hive一列中復雜的array或者map結構拆分成多行,
? LATERAL VIEW
? 用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias
? 解釋:用于和split, explode等UDTF一起使用,它能夠將一列資料拆成多行資料,在此基礎上可以對拆分后的資料進行聚合,
資料準備:
cd /export/servers/hivedatas
vim movie.txt
檔案內容如下: 資料欄位之間使用\t進行分割
《疑犯追蹤》 懸疑,動作,科幻,劇情
《Lie to me》 懸疑,警匪,動作,心理,劇情
《戰狼2》 戰爭,動作,災難
需求: 將電影分類中的陣列資料展開,結果如下:
《疑犯追蹤》 懸疑
《疑犯追蹤》 動作
《疑犯追蹤》 科幻
《疑犯追蹤》 劇情
《Lie to me》 懸疑
《Lie to me》 警匪
《Lie to me》 動作
《Lie to me》 心理
《Lie to me》 劇情
《戰狼2》 戰爭
《戰狼2》 動作
《戰狼2》 災難
實作步驟:
-
-
創建hive表
-
create table movie_info(
movie string,
category array<string>)
row format delimited fields terminated by "\t"
collection items terminated by ",";
-
-
加載資料
-
load data local inpath "/export/servers/hivedatas/movie.txt" into table movie_info;
-
-
按需求查詢資料
-
select
movie,
category_name
from
movie_info lateral view explode(category) table_tmp as category_name;
reflect函式
? reflect函式可以支持在sql中呼叫java中的自帶函式,秒殺一切udf函式,
需求1: 使用java.lang.Math當中的Max求兩列中最大值
實作步驟:
-
-
創建hive表
-
create table test_udf(col1 int,col2 int) row format delimited fields terminated by ',';
-
-
準備資料并加載資料
-
cd /export/servers/hivedatas
vim test_udf
檔案內容如下:
1,2
4,3
6,4
7,5
5,6
-
-
加載資料
-
hive (hive_explode)> load data local inpath '/export/servers/hivedatas/test_udf' overwrite into table test_udf;
-
-
使用java.lang.Math當中的Max求兩列當中的最大值
-
hive (hive_explode)> select reflect("java.lang.Math","max",col1,col2) from test_udf;
需求2: 檔案中不同的記錄來執行不同的java的內置函式
實作步驟:
-
-
創建hive表
-
hive (hive_explode)> create table test_udf2(class_name string,method_name string,col1 int , col2 int) row format delimited fields terminated by ',';
-
-
準備資料
-
cd /export/servers/hivedatas
vim test_udf2
檔案內容如下:
java.lang.Math,min,1,2
java.lang.Math,max,2,3
-
-
加載資料
-
hive (hive_explode)> load data local inpath '/export/servers/hivedatas/test_udf2' overwrite into table test_udf2;
-
-
執行查詢
-
hive (hive_explode)> select reflect(class_name,method_name,col1,col2) from test_udf2;
需求3: 判斷是否為數字
實作方式:
? 使用apache commons中的函式,commons下的jar已經包含在hadoop的classpath中,所以可以直接使用,
select reflect("org.apache.commons.lang.math.NumberUtils","isNumber","123")
視窗函式與分析函式
在sql中有一類函式叫做聚合函式,例如sum()、avg()、max()等等,這類函式可以將多行資料按照規則聚集為一行,一般來講聚集后的行數是要少于聚集前的行數的,但是有時我們想要既顯示聚集前的資料,又要顯示聚集后的資料,這時我們便引入了視窗函式,視窗函式又叫OLAP函式/分析函式,視窗函式兼具分組和排序功能,
視窗函式最重要的關鍵字是 partition by 和 order by,
具體語法如下:over (partition by xxx order by xxx)
sum、avg、min、max
準備資料
建表陳述句:
create table test_t1(
cookieid string,
createtime string, --day
pv int
) row format delimited
fields terminated by ',';
加載資料:
load data local inpath '/root/hivedata/test_t1.dat' into table test_t1;
cookie1,2020-04-10,1
cookie1,2020-04-11,5
cookie1,2020-04-12,7
cookie1,2020-04-13,3
cookie1,2020-04-14,2
cookie1,2020-04-15,4
cookie1,2020-04-16,4
開啟智能本地模式
SET hive.exec.mode.local.auto=true;
SUM函式和視窗函式的配合使用:結果和ORDER BY相關,默認為升序,
select cookieid,createtime,pv,
sum(pv) over(partition by cookieid order by createtime) as pv1
from test_t1;
select cookieid,createtime,pv,
sum(pv) over(partition by cookieid order by createtime rows between unbounded preceding and current row) as pv2
from test_t1;
select cookieid,createtime,pv,
sum(pv) over(partition by cookieid) as pv3
from test_t1;
select cookieid,createtime,pv,
sum(pv) over(partition by cookieid order by createtime rows between 3 preceding and current row) as pv4
from test_t1;
select cookieid,createtime,pv,
sum(pv) over(partition by cookieid order by createtime rows between 3 preceding and 1 following) as pv5
from test_t1;
select cookieid,createtime,pv,
sum(pv) over(partition by cookieid order by createtime rows between current row and unbounded following) as pv6
from test_t1;
pv1: 分組內從起點到當前行的pv累積,如,11號的pv1=10號的pv+11號的pv, 12號=10號+11號+12號
pv2: 同pv1
pv3: 分組內(cookie1)所有的pv累加
pv4: 分組內當前行+往前3行,如,11號=10號+11號, 12號=10號+11號+12號,
13號=10號+11號+12號+13號, 14號=11號+12號+13號+14號
pv5: 分組內當前行+往前3行+往后1行,如,14號=11號+12號+13號+14號+15號=5+7+3+2+4=21
pv6: 分組內當前行+往后所有行,如,13號=13號+14號+15號+16號=3+2+4+4=13,
14號=14號+15號+16號=2+4+4=10
? 如果不指定rows between,默認為從起點到當前行;
? 如果不指定order by,則將分組內所有值累加;
? 關鍵是理解rows between含義,也叫做window子句:
? preceding:往前
? following:往后
? current row:當前行
? unbounded:起點
? unbounded preceding 表示從前面的起點
? unbounded following:表示到后面的終點
? AVG,MIN,MAX,和SUM用法一樣,
row_number、rank、dense_rank、ntile
準備資料
cookie1,2020-04-10,1
cookie1,2020-04-11,5
cookie1,2020-04-12,7
cookie1,2020-04-13,3
cookie1,2020-04-14,2
cookie1,2020-04-15,4
cookie1,2020-04-16,4
cookie2,2020-04-10,2
cookie2,2020-04-11,3
cookie2,2020-04-12,5
cookie2,2020-04-13,6
cookie2,2020-04-14,3
cookie2,2020-04-15,9
cookie2,2020-04-16,7
CREATE TABLE test_t2 (
cookieid string,
createtime string, --day
pv INT
) ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
stored as textfile;
加載資料:
load data local inpath '/root/hivedata/test_t2.dat' into table test_t2;
-
ROW_NUMBER()使用
ROW_NUMBER()從1開始,按照順序,生成分組內記錄的序列,
SELECT
cookieid,
createtime,
pv,
ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rn
FROM test_t2;
-
RANK 和 DENSE_RANK使用
RANK() 生成資料項在分組中的排名,排名相等會在名次中留下空位 ,
DENSE_RANK()生成資料項在分組中的排名,排名相等會在名次中不會留下空位,
SELECT
cookieid,
createtime,
pv,
RANK() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rn1,
DENSE_RANK() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rn2,
ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY pv DESC) AS rn3
FROM test_t2
WHERE cookieid = 'cookie1';
-
NTILE
有時會有這樣的需求:如果資料排序后分為三部分,業務人員只關心其中的一部分,如何將這中間的三分之一資料拿出來呢?NTILE函式即可以滿足,
ntile可以看成是:把有序的資料集合平均分配到指定的數量(num)個桶中, 將桶號分配給每一行,如果不能平均分配,則優先分配較小編號的桶,并且各個桶中能放的行數最多相差1,
然后可以根據桶號,選取前或后 n分之幾的資料,資料會完整展示出來,只是給相應的資料打標簽;具體要取幾分之幾的資料,需要再嵌套一層根據標簽取出,
SELECT
cookieid,
createtime,
pv,
NTILE(2) OVER(PARTITION BY cookieid ORDER BY createtime) AS rn1,
NTILE(3) OVER(PARTITION BY cookieid ORDER BY createtime) AS rn2,
NTILE(4) OVER(ORDER BY createtime) AS rn3
FROM test_t2
ORDER BY cookieid,createtime;
其他一些視窗函式
lag,lead,first_value,last_value
-
LAG
LAG(col,n,DEFAULT) 用于統計視窗內往上第n行值第一個引數為列名,第二個引數為往上第n行(可選,默認為1),第三個引數為默認值(當往上第n行為NULL時候,取默認值,如不指定,則為NULL)
SELECT cookieid,
createtime,
url,
ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,
LAG(createtime,1,'1970-01-01 00:00:00') OVER(PARTITION BY cookieid ORDER BY createtime) AS last_1_time,
LAG(createtime,2) OVER(PARTITION BY cookieid ORDER BY createtime) AS last_2_time
FROM test_t4;
last_1_time: 指定了往上第1行的值,default為'1970-01-01 00:00:00'
cookie1第一行,往上1行為NULL,因此取默認值 1970-01-01 00:00:00
cookie1第三行,往上1行值為第二行值,2015-04-10 10:00:02
cookie1第六行,往上1行值為第五行值,2015-04-10 10:50:01
last_2_time: 指定了往上第2行的值,為指定默認值
cookie1第一行,往上2行為NULL
cookie1第二行,往上2行為NULL
cookie1第四行,往上2行為第二行值,2015-04-10 10:00:02
cookie1第七行,往上2行為第五行值,2015-04-10 10:50:01
-
LEAD
與LAG相反 LEAD(col,n,DEFAULT) 用于統計視窗內往下第n行值 第一個引數為列名,第二個引數為往下第n行(可選,默認為1),第三個引數為默認值(當往下第n行為NULL時候,取默認值,如不指定,則為NULL)
SELECT cookieid,
createtime,
url,
ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,
LEAD(createtime,1,'1970-01-01 00:00:00') OVER(PARTITION BY cookieid ORDER BY createtime) AS next_1_time,
LEAD(createtime,2) OVER(PARTITION BY cookieid ORDER BY createtime) AS next_2_time
FROM test_t4;
-
FIRST_VALUE
取分組內排序后,截止到當前行,第一個值
SELECT cookieid,
createtime,
url,
ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,
FIRST_VALUE(url) OVER(PARTITION BY cookieid ORDER BY createtime) AS first1
FROM test_t4;
-
LAST_VALUE
取分組內排序后,截止到當前行,最后一個值
SELECT cookieid,
createtime,
url,
ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,
LAST_VALUE(url) OVER(PARTITION BY cookieid ORDER BY createtime) AS last1
FROM test_t4;
如果想要取分組內排序后最后一個值,則需要變通一下:
SELECT cookieid,
createtime,
url,
ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,
LAST_VALUE(url) OVER(PARTITION BY cookieid ORDER BY createtime) AS last1,
FIRST_VALUE(url) OVER(PARTITION BY cookieid ORDER BY createtime DESC) AS last2
FROM test_t4
ORDER BY cookieid,createtime;
特別注意order by
如果不指定ORDER BY,則進行排序混亂,會出現錯誤的結果
SELECT cookieid,
createtime,
url,
FIRST_VALUE(url) OVER(PARTITION BY cookieid) AS first2
FROM test_t4;
cume_dist,percent_rank
這兩個序列分析函式不是很常用,注意: 序列函式不支持WINDOW子句
-
資料準備
d1,user1,1000
d1,user2,2000
d1,user3,3000
d2,user4,4000
d2,user5,5000
CREATE EXTERNAL TABLE test_t3 (
dept STRING,
userid string,
sal INT
) ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
stored as textfile;
加載資料:
load data local inpath '/root/hivedata/test_t3.dat' into table test_t3;
-
CUME_DIST 和order byd的排序順序有關系
CUME_DIST 小于等于當前值的行數/分組內總行數 order 默認順序 正序 升序 比如,統計小于等于當前薪水的人數,所占總人數的比例
SELECT
dept,
userid,
sal,
CUME_DIST() OVER(ORDER BY sal) AS rn1,
CUME_DIST() OVER(PARTITION BY dept ORDER BY sal) AS rn2
FROM test_t3;
rn1: 沒有partition,所有資料均為1組,總行數為5,
第一行:小于等于1000的行數為1,因此,1/5=0.2
第三行:小于等于3000的行數為3,因此,3/5=0.6
rn2: 按照部門分組,dpet=d1的行數為3,
第二行:小于等于2000的行數為2,因此,2/3=0.6666666666666666
-
PERCENT_RANK
PERCENT_RANK 分組內當前行的RANK值-1/分組內總行數-1
經調研 該函式顯示現實意義不明朗 有待于繼續考證
SELECT
dept,
userid,
sal,
PERCENT_RANK() OVER(ORDER BY sal) AS rn1, --分組內
RANK() OVER(ORDER BY sal) AS rn11, --分組內RANK值
SUM(1) OVER(PARTITION BY NULL) AS rn12, --分組內總行數
PERCENT_RANK() OVER(PARTITION BY dept ORDER BY sal) AS rn2
FROM test_t3;
rn1: rn1 = (rn11-1) / (rn12-1)
第一行,(1-1)/(5-1)=0/4=0
第二行,(2-1)/(5-1)=1/4=0.25
第四行,(4-1)/(5-1)=3/4=0.75
rn2: 按照dept分組,
dept=d1的總行數為3
第一行,(1-1)/(3-1)=0
第三行,(3-1)/(3-1)=1
grouping sets,grouping__id,cube,rollup
? 這幾個分析函式通常用于OLAP中,不能累加,而且需要根據不同維度上鉆和下鉆的指標統計,比如,分小時、天、月的UV數,
-
資料準備
2020-03,2020-03-10,cookie1
2020-03,2020-03-10,cookie5
2020-03,2020-03-12,cookie7
2020-04,2020-04-12,cookie3
2020-04,2020-04-13,cookie2
2020-04,2020-04-13,cookie4
2020-04,2020-04-16,cookie4
2020-03,2020-03-10,cookie2
2020-03,2020-03-10,cookie3
2020-04,2020-04-12,cookie5
2020-04,2020-04-13,cookie6
2020-04,2020-04-15,cookie3
2020-04,2020-04-15,cookie2
2020-04,2020-04-16,cookie1
CREATE TABLE test_t5 (
month STRING,
day STRING,
cookieid STRING
) ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
stored as textfile;
加載資料:
load data local inpath '/root/hivedata/test_t5.dat' into table test_t5;
-
GROUPING SETS
grouping sets是一種將多個group by 邏輯寫在一個sql陳述句中的便利寫法,
等價于將不同維度的GROUP BY結果集進行UNION ALL,
GROUPING__ID,表示結果屬于哪一個分組集合,
SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM test_t5
GROUP BY month,day
GROUPING SETS (month,day)
ORDER BY GROUPING__ID;
grouping_id表示這一組結果屬于哪個分組集合,
根據grouping sets中的分組條件month,day,1是代表month,2是代表day
等價于
SELECT month,NULL,COUNT(DISTINCT cookieid) AS uv,1 AS GROUPING__ID FROM test_t5 GROUP BY month UNION ALL
SELECT NULL as month,day,COUNT(DISTINCT cookieid) AS uv,2 AS GROUPING__ID FROM test_t5 GROUP BY day;
再如:
SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM test_t5
GROUP BY month,day
GROUPING SETS (month,day,(month,day))
ORDER BY GROUPING__ID;
等價于
SELECT month,NULL,COUNT(DISTINCT cookieid) AS uv,1 AS GROUPING__ID FROM test_t5 GROUP BY month
UNION ALL
SELECT NULL,day,COUNT(DISTINCT cookieid) AS uv,2 AS GROUPING__ID FROM test_t5 GROUP BY day
UNION ALL
SELECT month,day,COUNT(DISTINCT cookieid) AS uv,3 AS GROUPING__ID FROM test_t5 GROUP BY month,day;
-
CUBE
根據GROUP BY的維度的所有組合進行聚合,
SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM test_t5
GROUP BY month,day
WITH CUBE
ORDER BY GROUPING__ID;
等價于
SELECT NULL,NULL,COUNT(DISTINCT cookieid) AS uv,0 AS GROUPING__ID FROM test_t5
UNION ALL
SELECT month,NULL,COUNT(DISTINCT cookieid) AS uv,1 AS GROUPING__ID FROM test_t5 GROUP BY month
UNION ALL
SELECT NULL,day,COUNT(DISTINCT cookieid) AS uv,2 AS GROUPING__ID FROM test_t5 GROUP BY day
UNION ALL
SELECT month,day,COUNT(DISTINCT cookieid) AS uv,3 AS GROUPING__ID FROM test_t5 GROUP BY month,day;
-
ROLLUP
是CUBE的子集,以最左側的維度為主,從該維度進行層級聚合,
比如,以month維度進行層級聚合:
SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM test_t5
GROUP BY month,day
WITH ROLLUP
ORDER BY GROUPING__ID;
--把month和day調換順序,則以day維度進行層級聚合:
SELECT
day,
month,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM test_t5
GROUP BY day,month
WITH ROLLUP
ORDER BY GROUPING__ID;
(這里,根據天和月進行聚合,和根據天聚合結果一樣,因為有父子關系,如果是其他維度組合的話,就會不一樣)
微信搜索公眾號【五分鐘學大資料】 ,每周首發原創大資料技術文,深入框架原理,大廠面試真題等
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/271548.html
標籤:其他
上一篇:關于我以及我為什么要學習編程
