hive-rank()开窗函数系列

一、开窗函数简介

1、官方文档地址:

https://cwiki.apache.org/conf...

oracle,sqlserver都提供了窗口函数,但是在mysql5.5和5.6都没有提供窗口函数!

2、简介

窗口函数: 窗口+函数
窗口: 函数运行时计算的数据集的范围
函数: 运行的函数!

窗口函数和分组有什么区别?
①如果是分组操作,select后只能写分组后的字段
②如果是窗口函数,窗口函数是在指定的窗口内,对每条记录都执行一次函数
③如果是分组操作,有去重效果,而partition不去重!

3、相关函数说明

格式:函数over( partition by 字段 ,order by 字段 window_clause ),窗口的大小可以通过windows_clause来指定:

  • LEAD:往后第n行数据

LEAD (scalar_expression [,offset] [,default]): 返回当前行以下N行的指定列的列值!如果找不到,就采用默认值

  • LAG:往前第n行数据

LAG (scalar_expression [,offset] [,default]): 返回当前行以上N行的指定列的列值!如果找不到,就采用默认值

  • FIRST_VALUE:
    FIRST_VALUE(列名,[false(默认)]): 返回当前窗口指定列的第一个值,第二个参数如果为true,代表加入第一个值为null,跳过空值,继续寻找!
  • LAST_VALUE:

LAST_VALUE(列名,[false(默认)]): 返回当前窗口指定列的最后一个值,第二个参数如果为true,代表加入第一个值为null,跳过空值,继续寻找!

  • 统计类的函数(一般都需要结合over使用): min,max,avg,sum,count
  • 排名分析:RANK、ROW_NUMBER、DENSE_RANK、CUME_DIST、PERCENT_RANK
  • NTILE

把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。注意:n必须为int类型。

            注意:不是所有的函数在运行都是可以通过改变窗口的大小,来控制计算的数据集的范围!
                    所有的排名函数和LAG,LEAD,支持使用over(),但是在over()中不能定义 window_clause
            

(rows | range) between (unbounded | [num]) preceding and ([num] preceding | current row | (unbounded | [num]) following)

                (rows | range) between current row and (current row | (unbounded | [num]) following)
                (rows | range) between [num] following and (unbounded | [num]) following
                

特殊情况: ①在over()中既没有出现windows_clause,也没有出现order by,窗口默认为rows between UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING
②在over()中(没有出现windows_clause),指定了order by,窗口默认为rows between UNBOUNDED PRECEDING and CURRENT ROW

CURRENT ROW:当前行
n PRECEDING:往前n行数据
n FOLLOWING:往后n行数据
UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING表示到后面的终点

4、排名函数

注意:排名函数可以跟Over(),但是不能定义window_clause.
在计算名次前,需要先排序!

  • RANK: 允许并列,一旦有并列跳号!
  • ROW_NUMBER: 行号! 连续的,每个号之间差1!
  • DENSE_RANK: 允许并列,一旦有并列不跳号!
  • CUME_DIST: 从排序后的第一行到当前值之间数据 占整个数据集的百分比!
  • PERCENT_RANK: rank-1/ 总数据量-1
  • NTILE(x): 将数据集均分到X个组中,返回每条记录所在的组号
select  *,rank() over(order by score) ranknum,
ROW_NUMBER() over(order by score) rnnum,
DENSE_RANK() over(order by score) drnum,
CUME_DIST() over(order by score) cdnum,
PERCENT_RANK() over(order by score) prnum
from score
name subject score ranknum rnnum drnum cdnum prnum
大海 数学 56 1 1 1 0.083 0.0
宋宋 语文 64 2 2 2 0.166 0.0909
婷婷 语文 65 3 3 3 0.25 0.181
孙悟空 英语 68 4 4 4 0.33 0.272
婷婷 英语 78 5 5 5 0.416 0.363
宋宋 英语 84 6 6 6 0.583 0.454
大海 英语 84 6 7 6 0.583 0.454
婷婷 数学 85 8 8 7 0.666 0.636
宋宋 数学 86 9 9 8 0.75 0.727
孙悟空 语文 87 10 10 9 0.833 0.818
大海 语文 94 11 11 10 0.916 0.909
孙悟空 数学 95 12 12 11 1.0 1.0

二、示例

create table score(
name string,
subject string,
score int)
row format delimited fields terminated by "t";
load data local inpath '/opt/module/datas/score.txt' into table score;

  

-- 01 按照科目进行排名
-- 注意,就是新增了一列,该列展示排名信息,体会与group by 的区别
select *,rank() over(partition by subject order by score desc)
from score

-- 02 求每个学生的总分和总分排名,输出4条记录
-- 注意,如果只要总分,不要其他清单明细,那么使用group by 求和
select name,sumscore ,rank() over (order by sumscore desc) from
(select name,sum(score) sumscore from score group by name ) tmp

-- 03 求每个学生的成绩明细及给每个学生的总分和总分排名
-- 与上一个的区别,要每个学生的明细+排名,那么只能用窗口函数
select * ,DENSE_RANK() over (order by tmp.sumscore desc ) from
(select *,sum(score) over (partition by name) sumscore from score ) tmp

-- 只查询每个科目的成绩的前2名

-- 取清单+前多少名,可以用 子查询+rank

select * ,rn from

(select * ,rank() over (partition by subject order by score desc ) rn from score ) tmp where rn <=2

  
  
  

-- 查询学生成绩明细,并显示当前科目最高分

--如果只查一个max值,那么也可以用窗口函数,max or first

select *,max(score) over(partition by subject)

from score

或

select *,FIRST_VALUE(score) over(partition by subject order by score desc)

from score

  

--查询学生成绩,并显示当前科目最低分

select *,min(score) over(partition by subject)

from score

或

select *,FIRST_VALUE(score) over(partition by subject order by score )

from score


--(2)查询顾客的购买明细及月购买总额

-- 注意和下面一个的区别,没有order by ,体会窗口的概念,sum 是顶部到current ,这个表示所有到区间

select name,orderdate,cost,sum(cost) over(partition by name,substring(orderdate,1,7) )

from business

--(3)查询顾客的购买明细要将cost按照日期进行累加

-- 加了order by,窗口的概念

select name,orderdate,cost,sum(cost) over(partition by name order by orderdate )

from business

--(4)查询顾客的购买明细及顾客上次的购买时间

select name,orderdate,cost,lag(orderdate,1,'无数据') over(partition by name order by orderdate )

from business

(5) 查询顾客的购买明细及顾客下次的购买时间

select name,orderdate,cost,lead(orderdate,1,'无数据') over(partition by name order by orderdate )

from business

  

(6) 查询顾客的购买明细及顾客本月第一次购买的时间

select name,orderdate,cost,FIRST_VALUE(orderdate,true) over(partition by name,substring(orderdate,1,7) order by orderdate )

from business

  

(7) 查询顾客的购买明细及顾客本月最后一次购买的时间

select name,orderdate,cost,LAST_VALUE(orderdate,true) over(partition by name,substring(orderdate,1,7) order by orderdate rows between CURRENT row and UNBOUNDED FOLLOWING)

from business

  

(8)查询顾客的购买明细及顾客最近三次cost花费

最近三次: 当前和之前两次 或 当前+前一次+后一次

当前和之前两次:

select name,orderdate,cost,sum(cost) over(partition by name order by orderdate rows between 2 PRECEDING and CURRENT row)

from business

当前+前一次+后一次:

select name,orderdate,cost,sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING and 1 FOLLOWING)

from business

或

select name,orderdate,cost,cost+

lag(cost,1,0) over(partition by name order by orderdate )+

lead(cost,1,0) over(partition by name order by orderdate )

from business

  

(9) 查询前20%时间的订单信息

精确算法:

select *

from

(select name,orderdate,cost,cume_dist() over(order by orderdate ) cdnum

from business) tmp

where cdnum<=0.2

不精确计算:

select *

from

(select name,orderdate,cost,ntile(5) over(order by orderdate ) cdnum

from business) tmp

where cdnum=1

你可能感兴趣的:(hive,rank)