前提
over() 可以为 聚合函数,窗口函数和分析函数进行开窗操作;
开窗之后,每一行的数据都会对应一个数据窗口,这个数据窗口中的数据可能会随着行的变化而变化。
over(参数) 中可以指定的参数
over() 开窗开出来的数据是整个查询结果排除开窗操作,都执行完之后的数据。也可以说是开窗操作是在整个select查询结束后才执行的,因此开窗出来的数据也是在当前select的查询结果上进行划分的。
over中可以指定的参数(官方定义: WINDOW specification):
(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
rows 限定的是行所在的范围,range限定的是某一列的值所在的范围
- partition by col:按照col进行分区(类似于分组),每个分区拥有自己独立的数据窗口
- order by col:窗口中的数据按照col进行排序;
- current row :当前行
- n preceding:往前n行数据
- n following:往后n行数据
- unbounded:有两种边界值:unbounded preceding 表示所开窗出来的起始数据(最小值);unbounded following 表示所开窗出来的最后一行数据(最大值)。
两个常用的窗口函数,配合over开窗来使用
- lag(col, n) 获取当前行往前第n行col列的数据,也可以指定默认值。
- lead(col, n) 获取当前行往后第n行col列的数据。
常用的分析函数
- RANK 排名,排序相同时会重复,总数不变:1,1,3,4
- ROW_NUMBER 根据顺序计算,相同元素的排名不会重复 :1,2,3,4
- DENSE_RANK (稠密的排名) 相同元素的排名会重复,但是总数会减少:1,1,2,3
- NTILE(n), 为开窗出来的每行数据进行分组编号, n为指定的分组个数,返回每行数据的分组编号。当数据不能均匀分布时,默认从第一个组开始一次增加一个元素,不同组别之间的元素的个数最多相差一个元素
接下来我们通过例子,更加直观的学习上述所述的开窗相关的内容。
数据准备
name orderdate cost
------------------------
jack 2017-01-01 10
tony 2017-01-02 15
jack 2017-02-03 23
tony 2017-01-04 29
jack 2017-01-05 46
jack 2017-04-06 42
tony 2017-01-07 50
jack 2017-01-08 55
mart 2017-04-08 62
mart 2017-04-09 68
neil 2017-05-10 12
mart 2017-04-11 75
neil 2017-06-12 80
mart 2017-04-13 94
创建表并加载数据
create table business(
name string,
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
load data local inpath "/opt/module/datas/business.txt" into table business;
查询表中的所有元素
business.name business.orderdate business.cost
jack 2017-01-01 10
tony 2017-01-02 15
jack 2017-02-03 23
tony 2017-01-04 29
jack 2017-01-05 46
jack 2017-04-06 42
tony 2017-01-07 50
jack 2017-01-08 55
mart 2017-04-08 62
mart 2017-04-09 68
neil 2017-05-10 12
mart 2017-04-11 75
neil 2017-06-12 80
mart 2017-04-13 94
查询在2017年4月份购买过的顾客及总人数(over() 简单的使用)
select
name,
count(*) over()
from business
where substring(orderdate, 1, 7)='2017-04'
group by name;
结果:
+----+------------------------------------------------------------------------+
|name|count(1) OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)|
+----+------------------------------------------------------------------------+
|mart|2 |
|jack|2 |
+----+------------------------------------------------------------------------+
上述代码我们通过spark on hive的方式来访问hive中的数据,加快执行效率;如果没有spark,可以之间在hive shell中运行hql语句
partition by col测试:查询顾客的购买明细及月购买总额
val spark: SparkSession = SparkSession.builder()
.appName("HiveRead").master("local[*]")
.enableHiveSupport()
.config("spark.sql.warehouse.dir", "hdfs://hadoop102:9000/user/hive/warehouse")
.getOrCreate()
spark.sql(
"""
|select
| name,
| orderdate,
| cost,
| sum(cost) over(partition by month(orderdate))
|from business
|""".stripMargin
).show(false)
结果:
+----+----------+----+-------------------------------------------------------------------------------------------------------------------------------------+
|name|orderdate |cost|sum(CAST(cost AS BIGINT)) OVER (PARTITION BY month(CAST(orderdate AS DATE)) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)|
+----+----------+----+-------------------------------------------------------------------------------------------------------------------------------------+
|jack|2017-01-01|10 |205 |
|tony|2017-01-02|15 |205 |
|tony|2017-01-04|29 |205 |
|jack|2017-01-05|46 |205 |
|tony|2017-01-07|50 |205 |
|jack|2017-01-08|55 |205 |
|neil|2017-06-12|80 |80 |
|neil|2017-05-10|12 |12 |
|jack|2017-04-06|42 |341 |
|mart|2017-04-08|62 |341 |
|mart|2017-04-09|68 |341 |
|mart|2017-04-11|75 |341