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
之后,會執行一次sum
的reduce
過程,也就導致結果計算的是 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)的這一條數據會依舊保存)