Hive零基础从入门到实战 入门篇(十五) HiveQL:聚合函数、GROUP BY语句、HAVING语句

目录

 

前言

1. 聚合函数

2. GROUP BY语句

2.1 去重

2.2 与聚合函数一起使用

2.2.1 count(*)

2.2.2 count(col) 

2.2.3 count(distinct col) 

2.2.4 sum(col)

2.2.5 avg(col)

2.2.6 min(col)

2.2.7 max(col)

2.2.8 GROUP BY字段不全报错

3. HAVING语句


 

前言

本文介绍聚合函数、GROUP BY语句以及HAVING语句。在Hive中 GROUP BY 是使用频率极高的语句,工作中的几乎每一段HQL语句都会因为不同的原因使用它。

 

1. 聚合函数

下表为Hive内置的常用聚合函数。(col代表列名)

返回类型

函数名

描述

BIGINT

count(*)

count(col)

count(DISTINCT col)

返回检索到的行的总数,包括含有NULL值的行。

返回该列不是NULL的行的数量

返回该列唯一的且非NULL的行的数量

DOUBLE

sum(col)

sum(DISTINCT col)

对组内某列求和(包含重复值)

对组内某列求和(不包含重复值)

DOUBLE

avg(col),

avg(DISTINCT col)

对组内某列元素求平均值(包含重复值)

对组内某列元素求平均值(不包含重复值)

avg()函数会自动剔除NULL,总数除以非NULL个数

DOUBLE

min(col)

返回组内某列的最小值

DOUBLE

max(col)

返回组内某列的最大值

Hive中还有很多不常用但功能强大的聚合函数,如下表:

返回类型

函数名

描述

DOUBLE

variance(col),

var_pop(col)

返回组内某个数字列的方差

DOUBLE

var_samp(col)

返回组内某个数字列的无偏样本方差

DOUBLE

stddev_pop(col)

返回组内某个数字列的标准差

DOUBLE

stddev_samp(col)

返回组内某个数字列的无偏样本标准差

DOUBLE

covar_pop(col1, col2)

返回组内两个数字列的总体协方差

DOUBLE

covar_samp(col1, col2)

返回组内两个数字列的样本协方差

DOUBLE

corr(col1, col2)

返回组内两个数字列的皮尔逊相关系数

DOUBLE

percentile(BIGINT col, p)

返回组内某个列精确的第p位百分数,p必须在0和1之间

array

percentile(BIGINT col, array(p1 [, p2]...))

返回组内某个列精确的第p1,p2,……位百分数,p必须在0和1之间

DOUBLE

percentile_approx(DOUBLE col, p [, B])

返回组内数字列近似的第p位百分数(包括浮点数),参数B控制近似的精确度,B值越大,近似度越高,默认值为10000。当列中非重复值的数量小于B时,返回精确的百分数

array

percentile_approx(DOUBLE col, array(p1 [, p2]...) [, B])

同上,但接受并返回百分数数组

array

histogram_numeric(col, b)

使用b个非均匀间隔的箱子计算组内数字列的柱状图(直方图),输出的数组大小为b,double类型的(x,y)表示直方图的中心和高度(由于得出的是非均匀间隔的直方图,所以暂时没有发现这个函数的用途

array

collect_set(col)

返回消除了重复元素的数组

array

collect_list(col)

返回允许重复元素的数组

本文我们只介绍常用的聚合函数使用,2表中的聚合函数会在后续的进阶篇博客中详细介绍。

 

2. GROUP BY语句

GROUP BY语句 表示按照某些字段的值进行分组,有相同的值放到一起,有两种用法。

2.1 去重

在HQL语句中

  • 有WHERE语句的话,则GROUP BY语句紧跟在WHERE语句后,没有WHERE语句,则GROUP BY语句紧跟在表名后;
  • SELECT后的列名必须全部出现在GROUP BY语句后;
  • GROUP BY语句后不可使用SELECT语句中新起的别名。

具体语法如下:

SELECT 列名
FROM 表名
WHERE 列名 运算符 值 [AND 列名 运算符 值] [OR 列名 运算符 值]
GROUP BY 列名;

这个语句的含义是将列1和列2中一样的值放到一个组中,然后两列值的所有组合都只保留一个,最终达到对两列值所有组合去重的效果。

下面举例演示:

首先查出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 (app)> 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)

查询上面三个一样的字段,加上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,所以会产生很多无关的运行日志。

运行结果如下:

hive (app)> 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;
Query ID = root_20190528230950_04689e64-4528-4528-9f69-6c4fde0fc024
Total jobs = 1
Launching Job 1 out of 1
Number of reduce tasks not specified. Estimated from input data size: 1
In order to change the average load for a reducer (in bytes):
  set hive.exec.reducers.bytes.per.reducer=
In order to limit the maximum number of reducers:
  set hive.exec.reducers.max=
In order to set a constant number of reducers:
  set mapreduce.job.reduces=
Starting Job = job_1555398369811_0001, Tracking URL = http://hadoop:8088/proxy/application_1555398369811_0001/
Kill Command = /usr/local/hadoop/bin/hadoop job  -kill job_1555398369811_0001
Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1
2019-05-28 23:11:19,731 Stage-1 map = 0%,  reduce = 0%
2019-05-28 23:11:50,771 Stage-1 map = 100%,  reduce = 0%, Cumulative CPU 11.77 sec
2019-05-28 23:12:04,292 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 15.5 sec
MapReduce Total cumulative CPU time: 15 seconds 500 msec
Ended Job = job_1555398369811_0001
MapReduce Jobs Launched: 
Stage-Stage-1: Map: 1  Reduce: 1   Cumulative CPU: 15.5 sec   HDFS Read: 78220 HDFS Write: 10 SUCCESS
Total MapReduce CPU Time Spent: 15 seconds 500 msec
OK
user_id	platform	is_active
10600	2	1
Time taken: 136.253 seconds, Fetched: 1 row(s)

后续文章的结果展示为了节约篇幅会省略运行日志。

可以看到三行一样的数据只返回了一行,达到了去重的效果。

 

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.2 与聚合函数一起使用

GROUP BY与聚合函数一起使用时,必须将所有select语句中的非聚合函数字段全部GROUP BY,否则会报错。语法如下:

SELECT 列名
      ,aggregate_function(列名) AS num
FROM 表名
WHERE 列名 运算符 值 [AND 列名 运算符 值] [OR 列名 运算符 值]
GROUP BY 列名;

下面我们对常用的聚合函数进行逐一演示。

 

2.2.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.2.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

2.2.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

2.2.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

2.2.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

2.2.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

2.2.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

2.2.8 GROUP BY字段不全报错

当GROUP BY后的字段不全(没有包括所有select后的非聚合函数字段)时报错如下:

hive (app)> 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'

 

3. HAVING语句

在 HQL 中增加 HAVING 子句原因是,WHERE 关键字无法与聚合函数一起使用。HAVING 子句可以让我们筛选聚合后的数据,而且HAVING 子句中可以使用SELECT语句中用户自定义的列别名。

SELECT 列名
      ,aggregate_function(列名) AS num
FROM 表名
WHERE 列名 运算符 值 [AND 列名 运算符 值] [OR 列名 运算符 值]
GROUP BY 列名
HAVING num 运算符 值 [AND 列名 运算符 值] [OR 列名 运算符 值];
  • 查询三天内每天每个平台每个版本有多少个用户使用,取出大于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;

运行结果如下: 

date_8	platform	app_version	num
20190102	1	1.1	142
20190102	1	1.5	148
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

 


能看到这里的同学,就右上角点个赞顺便关注我吧,3Q~

你可能感兴趣的:(Hive零基础从入门到实战 入门篇(十五) HiveQL:聚合函数、GROUP BY语句、HAVING语句)