本文部分參考自:https://blog.csdn.net/qq_23897391/article/details/90897373
Hive第六天——Hive函數
自己的話:千里之行,始於足下。
每天都要保持前進,我勢必要有強勁的實力,再跟明天的自己問好。
GROUP BY語句、HAVING語句、ORDER BY語句
一、GROUP BY語句
GROUP BY語句 表示按照某些字段的值進行分組,有相同的值放到一起,有兩種用法。
1.去重
(1)功能:
在HQL語句中
有WHERE語句的話,則GROUP BY語句緊跟在WHERE語句後,沒有WHERE語句,則GROUP BY語句緊跟在表名後;
SELECT後的列名必須全部出現在GROUP BY語句後;
GROUP BY語句後不可使用SELECT語句中新起的別名。
具體語法如下:
SELECT 列名
FROM 表名
WHERE 列名 運算符 值 [AND 列名 運算符 值] [OR 列名 運算符 值]
GROUP BY 列名;
這個語句的含義是將列1和列2中一樣的值放到一個組中,然後兩列值的所有組合都只保留一個,最終達到對兩列值所有組合去重的效果。
(2)舉例:
<1>首先查出user_id爲10600的所有記錄,可以看到三條記錄的user_id、platform、is_active三個字段是相同的,只是時間和使用次數不同。
SELECT user_id,platform,use_cnt,is_active,date_8
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
AND user_id = 10600;
運行結果如下:
hive > SELECT user_id,platform,use_cnt,is_active,date_8
> FROM app.t_od_use_cnt
> WHERE date_8 >= 20190101
> AND user_id = 10600;
OK
user_id platform use_cnt is_active date_8
10600 2 46 1 20190101
10600 2 49 1 20190102
10600 2 11 1 20190103
Time taken: 0.169 seconds, Fetched: 3 row(s)
<2>查詢上面三個一樣的字段,加上GROUP BY語句,命令如下:
SELECT user_id,platform,is_active
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
AND user_id = 10600
GROUP BY user_id
,platform
,is_active;
使用GROUP BY語句Hive會產生Mapreduce,所以會產生很多無關的運行日誌。
運行結果如下:
user_id platform is_active
10600 2 1
可以看到三行一樣的數據只返回了一行,達到了去重的效果。
<3>Hive中去重還可以使用DISTINCT關鍵字,用法如下:
SELECT DISTINCT user_id,platform,is_active
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
AND user_id = 10600;
運行結果是一樣的,但去重時不建議使用DISTINCT,因爲當數據量很大時會產生數據傾斜,導致DISTINCT運行效率相比GROUP BY 會低很多。當數據量較小時兩者差距則不大,甚至可能DISTINCT效率更高。但在實際工作中數據量動輒千萬行上億行,所以強烈推薦養成使用GROUP BY去重的習慣。
2.與聚合函數一起使用(*)
GROUP BY與聚合函數一起使用時,必須將所有select語句中的非聚合函數字段全部GROUP BY,否則會報錯。語法如下:
SELECT 列名
,aggregate_function(列名) AS num
FROM 表名
WHERE 列名 運算符 值 [AND 列名 運算符 值] [OR 列名 運算符 值]
GROUP BY 列名;
(1) count(*)
查詢三天內每天有多少條記錄
SELECT date_8,count(*) AS num
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
GROUP BY date_8;
運行結果如下:
date_8 num
20190101 1000
20190102 1300
20190103 1500
(2) count(col)
查詢三天內每天每個平臺每個版本有多少個用戶使用
SELECT date_8,platform,app_version,count(user_id) AS num
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
GROUP BY date_8,platform,app_version;
運行結果如下:
date_8 platform app_version num
20190101 1 1.1 121
20190101 1 1.2 91
20190101 1 1.3 106
20190101 1 1.4 102
20190101 1 1.5 101
20190101 2 1.1 93
20190101 2 1.2 94
20190101 2 1.3 93
20190101 2 1.4 92
20190101 2 1.5 107
20190102 1 1.1 142
20190102 1 1.2 124
20190102 1 1.3 128
20190102 1 1.4 115
20190102 1 1.5 148
20190102 2 1.1 126
20190102 2 1.2 109
20190102 2 1.3 135
20190102 2 1.4 136
20190102 2 1.5 137
20190103 1 1.1 136
20190103 1 1.2 155
20190103 1 1.3 155
20190103 1 1.4 148
20190103 1 1.5 164
20190103 2 1.1 161
20190103 2 1.2 137
20190103 2 1.3 146
20190103 2 1.4 161
20190103 2 1.5 137
(3)count(distinct col)
查詢三天內每天每個平臺下有多少個版本
SELECT date_8,platform,count(DISTINCT app_version) AS num
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
GROUP BY date_8,platform;
運行結果如下:
date_8 platform num
20190101 1 5
20190101 2 5
20190102 1 5
20190102 2 5
20190103 1 5
20190103 2 5
(4)sum(col)
查詢三天內每天每個平臺下的用戶共使用了多少次
SELECT date_8,platform,sum(use_cnt) AS num
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
GROUP BY date_8,platform;
運行結果如下:
date_8 platform num
20190101 1 13495
20190101 2 12596
20190102 1 16859
20190102 2 16356
20190103 1 19894
20190103 2 19431
(5)avg(col)
查詢三天內每天每個平臺下的用戶平均使用了多少次
SELECT date_8,platform,avg(use_cnt) AS num
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
GROUP BY date_8,platform;
運行結果如下:
date_8 platform num
20190101 1 25.9021113243762
20190101 2 26.296450939457202
20190102 1 25.660578386605785
20190102 2 25.43701399688958
20190103 1 26.24538258575198
20190103 2 26.18733153638814
(6)min(col)
查詢三天內每天每個平臺下的用戶最少使用了多少次
SELECT date_8,platform,min(use_cnt) AS num
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
GROUP BY date_8,platform;
運行結果如下:
date_8 platform num
20190101 1 1
20190101 2 1
20190102 1 1
20190102 2 1
20190103 1 1
20190103 2 1
(7)max(col)
查詢三天內每天每個平臺下的用戶最多使用了多少次
SELECT date_8,platform,max(use_cnt) AS num
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
GROUP BY date_8,platform;
運行結果如下:
date_8 platform num
20190101 1 50
20190101 2 50
20190102 1 50
20190102 2 50
20190103 1 50
20190103 2 50
(8) GROUP BY字段不全報錯
當GROUP BY後的字段不全(沒有包括所有select後的非聚合函數字段)時報錯如下:
hive > SELECT date_8,platform,max(use_cnt) AS num
> FROM app.t_od_use_cnt
> WHERE date_8 >= 20190101
> GROUP BY date_8;
FAILED: SemanticException [Error 10025]: Line 2:7 Expression not in GROUP BY key 'platform'
二、HAVING語句
1.在 HQL 中增加 HAVING 子句原因
WHERE 關鍵字無法與聚合函數一起使用。HAVING 子句可以讓我們篩選聚合後的數據,而且HAVING 子句中可以使用SELECT語句中用戶自定義的列別名。
SELECT 列名,aggregate_function(列名) AS num
FROM 表名
WHERE 列名 運算符 值 [AND 列名 運算符 值] [OR 列名 運算符 值]
GROUP BY 列名
HAVING num 運算符 值 [AND 列名 運算符 值] [OR 列名 運算符 值];
2.having與where不同點
(1)where針對表中的列發揮作用,查詢數據;having針對查詢結果中的列發揮作用,篩選數據。
(2)where後面不能寫分組函數,而having後面可以使用分組函數。
(3)having只用於group by分組統計語句。
3.舉例:
(1)查詢三天內每天每個平臺每個版本有多少個用戶使用,取出大於130個用戶使用的記錄
SELECT date_8,platform,app_version,count(user_id) AS num
FROM app.t_od_use_cnt
WHERE date_8 >= 20190101
GROUP BY date_8,platform,app_version
HAVING num > 130;
(2)求每個學生的平均分數
select s_id ,avg(s_score) from score group by s_id;
(3)求每個學生平均分數大於85的人
select s_id ,avg(s_score) avgscore from score group by s_id having avgscore > 85;
三、排序語句
1.全局排序(Order By)
(1)使用 ORDER BY 子句排序
- ASC(ascend): 升序(默認)
- DESC(descend): 降序
(2)需要注意:
使用ORDER BY需要注意:
- ORDER BY永遠只能在查詢語句的最後;
- ORDER BY可以對多個字段進行排序,按照字段的順序進行依次排序;
- 默認是從小到大升序排序,每個字段後面都可以加DESC關鍵字,表示對該字段進行降序排序;
- ORDER BY是全局排序,會有一個所有的數據都通過一個REDUCE進行處理的過程,十分影響運行效率;
- ORDER BY中可以使用SELECT語句中用戶自定義的列別名。
(3)舉例:
<1>查詢學生的成績,並按照分數降序排列
SELECT * FROM student s LEFT JOIN score sco ON s.s_id = sco.s_id ORDER BY sco.s_score DESC;
<2>查詢學生的成績,並按照分數升序排列
SELECT * FROM student s LEFT JOIN score sco ON s.s_id = sco.s_id ORDER BY sco.s_score asc;
<3>按照別名排序:按照分數的平均值排序
select s_id ,avg(s_score) avg from score group by s_id order by avg;
<4>多個列排序:按照學生id和平均成績進行排序
select s_id ,avg(s_score) avg from score group by s_id order by s_id,avg;
2.局部排序(Sort By)(不常用)
(1)功能:
每個MapReduce內部進行排序,對全局結果集來說不是排序。
1)設置reduce個數
set mapreduce.job.reduces=3;
2)查看設置reduce個數
set mapreduce.job.reduces;
(2)舉例:
查詢成績按照成績降序排列:
select * from score sort by s_score;
將查詢結果導入到文件中(按照成績降序排列):
insert overwrite local directory '/export/servers/hivedatas/sort' select * from score sort by s_score;
3.分區排序(DISTRIBUTE BY)(不常用)
(1)簡介:
類似MR中partition,進行分區,結合sort by使用。
(2)注意:
Hive要求DISTRIBUTE BY語句要寫在SORT BY語句之前。
對於distribute by進行測試,一定要分配多reduce進行處理,否則無法看到distribute by的效果。
(3)舉例:
先按照學生id進行分區,再按照學生成績進行排序。
<1>設置reduce的個數,將我們對應的s_id劃分到對應的reduce當中去
set mapreduce.job.reduces=7;
<2>通過distribute by 進行數據的分區
insert overwrite local directory '/home/sort' select * from score distribute by s_id sort by s_score;