在mysql5.5,5.6版本,不支持窗口函数!在oracle和sqlserver中支持窗口函数!
hive支持窗口函数!
窗口函数=函数+窗口
函数: 要运行的函数!只有以下函数称为窗口函数!
开窗函数:
LEAD: 用来返回当前行以下行的数据!
用法: LEAD (列名 [,offset] [,default])
offset是偏移量,默认为1,
default: 取不到值就使用默认值代替
LAG: 用来返回当前行以上行的数据!
用法: LAG (列名 [,offset] [,default])
offset是偏移量,默认为1,
default: 取不到值就使用默认值代替
FIRST_VALUE: 返回指定列的第一个值
用法: FIRST_VALUE(列名,[false是否忽略null值])
LAST_VALUE:返回指定列的最后一个值
用法: LAST_VALUE(列名,[false是否忽略null值])
标准的聚集函数:MAX,MIN,AVG,COUNT,SUM
分析排名函数:
RANK
ROW_NUMBER
DENSE_RANK
CUME_DIST
PERCENT_RANK
NTILE
窗口: 函数在运行时,计算的结果集的范围!
窗口函数指以上特定函数在运算时,可以自定义一个窗口(计算的范围)
函数 over( [partition by 字段1,字段2] [order by 字段 asc|desc] [window clause] )
partition by : 根据某些字段对整个数据集进行分区!
order by: 对分区或整个数据集中的数据按照某个字段进行排序!
注意: 如果对数据集进行了分区,那么窗口的范围不能超过分区的范围!
既窗口必须在区内指定!
(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
定义起始行和终止行的范围即可!
两个特殊情况:
When both ORDER BY and WINDOW clauses are missing, the WINDOW specification defaults to ROW BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING.
当over()既没有写order by,也没有写window 子句,此时窗口默认等同于上无边界到下无边界(整个数据集)
When ORDER BY is specified with missing WINDOW clause, the WINDOW specification defaults to RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.
当over()中,指定了order by 但是没有指定 window 子句,此时窗口默认等同于 上无边界到当前行
支持Over(),但是不支持在over中定义windows子句的函数:
The OVER clause supports the following functions, but it does not support a window with them (see HIVE-4797):
Ranking functions: Rank, NTile, DenseRank, CumeDist, PercentRank.
Lead and Lag functions
create table business(
name string,
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
加载数据:
load data local inpath '/home/jaffe/hivedatas/test5' into table business;
需求:
(1)查询在2017年4月份购买过的顾客及总人数
(2)查询顾客的购买明细及月购买总额
(3)查询顾客的购买明细要将cost按照日期进行累加
(4)查询顾客的购买明细及顾客上次的购买时间
(5) 查询顾客的购买明细及顾客下次的购买时间
(6) 查询顾客的购买明细及顾客本月第一次购买的时间
(7) 查询顾客的购买明细及顾客本月最后一次购买的时间
(8) 查询顾客的购买明细及顾客最近三次cost花费
(9) 查询前20%时间的订单信息
思路:
①where 过滤 2017年4月份的数据
②求顾客总人数
总人数 不等于 总人次
查询在2017年4月份购买过的总人数
select '2017-04',count(*)
from
(select name
from business
where year(orderdate)=2017 and month(orderdate)=4
group by name)tmp
select *
from business
where substring(orderdate,1,7)='2017-04'
错误:
select count(*)
from business
where year(orderdate)=2017 and month(orderdate)=4
group by name
聚集函数是分组后在组内统计,聚集函数默认工作的范围(窗口)是组内!
窗口函数对窗口中的每一条记录都进行计算!
使用窗口函数: 需要指定count()运行的窗口大小为整个结果集而不是组内!
查询在2017年4月份购买过的顾客及总人数
select name,count(*) over(ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
from business
where year(orderdate)=2017 and month(orderdate)=4
group by name
统计明细,为每条明细都附加一个总的结果,一般使用窗口函数!
如果只要结果不要明细,没有必要使用窗口函数!
以上窗口函数还可以简写:
select name,count(*) over()
from business
where year(orderdate)=2017 and month(orderdate)=4
group by name
按照顾客和月份分区,在区内计算所有的购买金额的总和!
select *,sum(cost) over(partition by name,substring(orderdate,1,7) ) total_month_cost
from business
select *,sum(cost) over(partition by name order by orderdate ) total_cost
from business
lag不支持在over()中定义window子句!
select *,lag(orderdate,1,'无') over(partition by name order by orderdate ) total_cost
from business
select *,lead(orderdate,1,'无') over(partition by name order by orderdate ) total_cost
from business
让窗口可以取到第一个值
select *,first_value(orderdate) over(partition by name,substring(orderdate,1,7) order by orderdate ) first_date
from business
让窗口可以取到最后一个值
select *,last_value(orderdate) over(partition by name,substring(orderdate,1,7) order by orderdate
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) last_date
from business
最近三次:
如果当前购买记录是最新的一次,那么最近三次就是当前此次+之前两次
如果当前购买记录不是最新的一次,是历史记录,那么也有可能取当前记录+上下各一次!
当前此次+之前两次:
select *,sum(cost) over(partition by name order by orderdate
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) mycost
from business
当前记录+上下各一次:
select *,sum(cost) over(partition by name order by orderdate
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) mycost
from business
(1)精确计算:
函数:CUME_DIST
select *
from
(select *,CUME_DIST() over(order by orderdate) cdnum
from business)t1
where cdnum<=0.2
(2)不太精确:
函数: ntile()
select *
from
(select *,ntile(5) over(order by orderdate) ntilenum
from business)t1
where ntilenum=1