本文部分参考自:https://blog.csdn.net/qq_23897391/article/details/90897373
自己的话:千里之行,始于足下。
每天都要保持前进,我势必要有强劲的实力,再跟明天的自己问好。
GROUP BY语句 表示按照某些字段的值进行分组,有相同的值放到一起,有两种用法。
在HQL语句中
有WHERE语句的话,则GROUP BY语句紧跟在WHERE语句后,没有WHERE语句,则GROUP BY语句紧跟在表名后;
SELECT后的列名必须全部出现在GROUP BY语句后;
GROUP BY语句后不可使用SELECT语句中新起的别名。
具体语法如下:
SELECT 列名
FROM 表名
WHERE 列名 运算符 值 [AND 列名 运算符 值] [OR 列名 运算符 值]
GROUP BY 列名;
这个语句的含义是将列1和列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去重的习惯。
GROUP BY与聚合函数一起使用时,必须将所有select语句中的非聚合函数字段全部GROUP BY,否则会报错。语法如下:
SELECT 列名
,aggregate_function(列名) AS num
FROM 表名
WHERE 列名 运算符 值 [AND 列名 运算符 值] [OR 列名 运算符 值]
GROUP BY 列名;
查询三天内每天有多少条记录
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
查询三天内每天每个平台每个版本有多少个用户使用
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
查询三天内每天每个平台下有多少个版本
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
查询三天内每天每个平台下的用户共使用了多少次
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
查询三天内每天每个平台下的用户平均使用了多少次
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
查询三天内每天每个平台下的用户最少使用了多少次
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
查询三天内每天每个平台下的用户最多使用了多少次
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
当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'
WHERE 关键字无法与聚合函数一起使用。HAVING 子句可以让我们筛选聚合后的数据,而且HAVING 子句中可以使用SELECT语句中用户自定义的列别名。
SELECT 列名,aggregate_function(列名) AS num
FROM 表名
WHERE 列名 运算符 值 [AND 列名 运算符 值] [OR 列名 运算符 值]
GROUP BY 列名
HAVING num 运算符 值 [AND 列名 运算符 值] [OR 列名 运算符 值];
(1)where针对表中的列发挥作用,查询数据;having针对查询结果中的列发挥作用,筛选数据。
(2)where后面不能写分组函数,而having后面可以使用分组函数。
(3)having只用于group by分组统计语句。
(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;
使用ORDER BY需要注意:
<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;
每个MapReduce内部进行排序,对全局结果集来说不是排序。
1)设置reduce个数
set mapreduce.job.reduces=3;
2)查看设置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;
类似MR中partition,进行分区,结合sort by使用。
Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前。
对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。
先按照学生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;