Loading

Hive Sql的窗口函数

date: 2019-08-30 11:02:37
updated: 2019-08-30 14:40:00

Hive Sql的窗口函数

1. count、sum、avg、max、min

sum 为例

# 按照 year 来分组,统计每一年的总和
# 结果:每个月的值都是本年的总和
sum(val) over(partition by year)

# 按照 year 来分组,按照 month 来排序
# 结果:n 月的值是本年 1 - n 月的累计值
sum(val) over(partition by year order by month)

通过 explain select ... 来查看语句解析,可以简单理解为,在每一次 order by 之后,会执行一次 sumreduce 过程,也就导致结果计算的是 1 - n 月的累计值

2. rows between

sum 为例

# 按照 year 分组,按照 month 排序,计算前3行和后1行的总和
sum(val) over(partition by year order by month rows between 3 preceding and 1 following)
  • preceding:往前
  • following:往后
  • current row:当前行
  • unbounded:起点
    • unbounded preceding:表示从前面的起点
    • unbounded following:表示到后面的终点
# 以下两种方式是等效的
sum(val) over(partition by year)
sum(val) over(partition by year rows between unbounded preceding and unbounded following)

# 以下两种方式是等效的
sum(val) over(partition by year order by month)
sum(val) over(partition by year order by month rows between unbounded preceding and current row)

# 以下两种方式不等效
sum(val) over(partition by year rows between unbounded preceding and current row)
sum(val) over(partition by year order by month rows between unbounded preceding and current row)
# current row 应该是和 order by 同时出现,要不然会导致数据错位

3. ntile

切片:用于将分组数据按照顺序切分成n片,返回当前切片值;不支持 rows between;如果切片不均匀,默认增加第一个切片的分布(比如有6条数据,分4组,数量依次为2 2 1 1)

# 统计一个月内,val 最多的前 1/n 
ntile(n) over(partition by month order by val desc) as rn
rn = 1 就是最终想要的结果,前提是数据可以被均匀分片

4. row_number、rank、dense_rank

  • row_number:行号
  • rank:排名——结果中可能有空位 eg:1 2 2 4
  • dense_rank:排名——结果中无空位 eg:1 2 2 3

5. cume_dist

计算公式:(小于等于当前值的行数 / 分组内的总行数)

# 统计小于等于当前薪水的人占部门内总人数的比例
cume_dist() over(partition by dept order by salary)

6. percent_rank

计算公式:(分组内当前行的rank值 - 1 / 分组内总行数 - 1)

7. lag(col, n, DEFAULT)

统计窗口内往上第 n 行值

三个参数分别是:列名;往上第 n 行(可选,默认是1);当往上第 n 行为 NULL 的时候,取默认值,如不指定,则为 NULL

8. lead(col, n, DEFAULT)

统计窗口内往下第 n 行值

三个参数分别是:列名;往下第 n 行(可选,默认是1);当往下第 n 行为 NULL 的时候,取默认值,如不指定,则为 NULL

9. first_value(col)

取分组内排序后,取第一个的 col

first_value(col) over(partition by ... order by ...)

10. last_value(col)

取分组内排序后,截止到当前行,最后一个的 col => 相当于分组排序后,取当前这一行的 col

last_value(col) over(partition by ... order by ...)

如果不指定 order by,则默认按照记录在文件中的偏移量进行排序,会出现错误的结果

如果要取分组内排序后最后一个 col,可以换成下面的形式

first_value(col) over(partition by ... order by ... desc)

11. grouping sets

在一个 group by 查询中,根据不同的维度组合进行聚合,等价于将不同维度的 group by 结果集进行 union all

select year, month, count(1)a, grouping__id 
from ...
group by year, month
grouping sets(year, month, (year, month))
order by grouping__id

等价于

select year, 'null' as month, count(1)a, 1 as grouping__id 
from ...
group by year, month
union all
select 'null' as year, month, count(1)a, 2 as grouping__id 
from ...
group by month
union all
select year, month, count(1)a, 3 as grouping__id 
from ...
group by year, month

grouping sets (col1, col2 ...) 使用前必须要先写 group by (col1, col2 ...), grouping sets 表示在 group by 括号内出现的字段组合的情况,所以 grouping sets 出现的字段肯定是在 group by 中出现过的

grouping__id 表示结果属于哪一个分组集合,只能和 grouping sets 组合着用,单独使用报错。有两个下划线!!!

12. cube

根据 group by 的维度的所有组合进行聚合。

select year, month, count(1)a, grouping__id 
from ...
group by year, month
with cube
order by grouping__id

等价于以下四种情况 union all
1. 相当于直接 count(1)a
2. 按照 year 来分组
3. 按照 month 来分组
4. 按照 year&month 来分组

13. rollup

是 cube 的子集,以最左侧的维度为主,从该维度进行层级聚合。

select year, month, count(1)a, grouping__id 
from ...
group by year, month
with rollup
order by grouping__id

等价于先进行 with cube操作,即以下四种情况 union all
1. 相当于直接 count(1)a
2. 按照 year 来分组
3. 按照 month 来分组
4. 按照 year&month 来分组

然后 year 是最左侧的维度,则按照 year 来进行层级聚合,过滤掉 year 为 NULL 的记录(但是第1中情况对所有数据进行count(1)的这一条数据会依旧保存)
posted @ 2020-10-22 09:41  猫熊小才天  阅读(1074)  评论(0编辑  收藏  举报