窗口函数over简介

先来看一下这个需求:求每个部门的员工信息以及部门的平均工资。在mysql中如何实现呢

SELECT emp.*, avg_sal
FROM empJOIN (SELECT deptno, round(AVG(ifnull(sal, 0))) AS avg_salFROM empGROUP BY deptno) tON emp.deptno = t.deptno
ORDER BY deptno;select emp.*,(select avg(ifnull(sal,0)) from emp B where B.deptno = A.deptno )
from emp A;

通过这个需求我们可以看到,如果要查询详细记录和聚合数据,必须要经过**两次查询**,比较麻烦。

这个时候,我们使用窗口函数,会方便很多。那么窗口函数是什么呢?

特点

-1) 窗口函数又名开窗函数,属于分析函数的一种。
-2) 是一种用于解决复杂报表统计需求的函数。
-3) 窗口函数常用于计算基于组的某种值,它和聚合函数的不同之处是:对于每个组返回多行,而聚合函数对于每个组只返回一行。
简单的说窗口函数对每条详细记录开一个窗口,进行聚合统计的查询
-4) 开窗函数指定了分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化。
-5) 窗口函数一般不单独使用
-6) 窗口函数内也可以分组和排序

参考下图:

**注意:**默认mysql老版本没有支持,在最新的8.0版本中支持, Oracle和Hive中都支持窗口函数

基本案例演示

数据准备(order.txt)

姓名 购买日期购买数量
saml    2018-01-01      10
saml    2018-01-08      55
tony    2018-01-07      50
saml    2018-01-05      46
tony    2018-01-04      29
tony    2018-01-02      15
saml    2018-02-03      23
mart    2018-04-13      94
saml    2018-04-06      42
mart    2018-04-11      75
mart    2018-04-09      68
mart    2018-04-08      62
neil    2018-05-10      12
neil    2018-06-12      80
drop table t_order;
--1. 创建order表:
create table if not exists t_order
(name      string,orderdate string,cost      int
) row format delimited fields terminated by '\t';
--2. 加载数据:
load data local inpath "/data/order.txt" into table t_order;
select * from t_order;

需求:查询每个订单的信息,以及订单的总数

– 1.不使用窗口函数

-- 查询所有明细
select * from t_order;
# 查询总量
select count(*) from t_order;

– 2.使用窗口函数:通常格式为 可用函数+over()函数

select *, count(*) over() from t_order;
+----+----------+----+--+
|name|orderdate |cost|c1|
+----+----------+----+--+
|    |NULL      |NULL|15|
|neil|2018-06-12|80  |15|
|neil|2018-05-10|12  |15|
|mart|2018-04-08|62  |15|
|mart|2018-04-09|68  |15|
|mart|2018-04-11|75  |15|
|saml|2018-04-06|42  |15|
|mart|2018-04-13|94  |15|
|saml|2018-02-03|23  |15|
|tony|2018-01-02|15  |15|
|tony|2018-01-04|29  |15|
|saml|2018-01-05|46  |15|
|tony|2018-01-07|50  |15|
|saml|2018-01-08|55  |15|
|saml|2018-01-01|10  |15|
+----+----------+----+--+

注意:

窗口函数是针对每一行数据的.

如果over中没有指定参数,默认窗口大小为全部结果集

需求:查询在2018年1月份购买过的顾客购买明细及总人数

select *,count(*) over() from t_order
where substring(orderdate,1,7)='2018-01'
+----+----------+----+--+
|name|orderdate |cost|c1|
+----+----------+----+--+
|tony|2018-01-02|15  |6 |
|tony|2018-01-04|29  |6 |
|saml|2018-01-05|46  |6 |
|tony|2018-01-07|50  |6 |
|saml|2018-01-08|55  |6 |
|saml|2018-01-01|10  |6 |
+----+----------+----+--+

distribute by子句

在over窗口中进行分组,对某一字段进行分组统计,窗口大小就是同一个组的所有记录

语法:
over(distribute by colname[,colname.....])

需求:查看顾客的购买明细及月购买总额

select *,sum(cost) over(distribute by month(orderdate)) sum
from t_order;+----+----------+----+----+
|name|orderdate |cost|sum |
+----+----------+----+----+
|    |NULL      |NULL|NULL|
|saml|2018-01-01|10  |205 |
|tony|2018-01-02|15  |205 |
|tony|2018-01-04|29  |205 |
|saml|2018-01-05|46  |205 |
|tony|2018-01-07|50  |205 |
|saml|2018-01-08|55  |205 |
|saml|2018-02-03|23  |23  |
|mart|2018-04-13|94  |341 |
|mart|2018-04-08|62  |341 |
|mart|2018-04-09|68  |341 |
|mart|2018-04-11|75  |341 |
|saml|2018-04-06|42  |341 |
|neil|2018-05-10|12  |12  |
|neil|2018-06-12|80  |80  |
+----+----------+----+----+

需求:查看顾客的购买明细及每个顾客的月购买总额

select *,sum(cost) over(distribute by month(orderdate),name)
from t_order;
+----+----------+----+----+
|name|orderdate |cost|c1  |
+----+----------+----+----+
|    |NULL      |NULL|NULL|
|saml|2018-01-01|10  |111 |
|saml|2018-01-05|46  |111 |
|saml|2018-01-08|55  |111 |
|tony|2018-01-02|15  |94  |
|tony|2018-01-04|29  |94  |
|tony|2018-01-07|50  |94  |
|saml|2018-02-03|23  |23  |
|mart|2018-04-09|68  |299 |
|mart|2018-04-11|75  |299 |
|mart|2018-04-13|94  |299 |
|mart|2018-04-08|62  |299 |
|saml|2018-04-06|42  |42  |
|neil|2018-05-10|12  |12  |
|neil|2018-06-12|80  |80  |
+----+----------+----+----+

sort by子句

sort by子句会让输入的数据强制排序 (强调:当使用排序时,窗口会在组内逐行变大)

语法:  over([distribute by colname] [sort by colname [desc|asc]])

需求:查看顾客的购买明细及每个顾客的月购买总额,并且按照日期降序排序

select *, sum(cost) over (distribute by month(orderdate),name sort by orderdate desc)
from t_order;
+----+----------+----+----+
|name|orderdate |cost|c1  |
+----+----------+----+----+
|    |NULL      |NULL|NULL|
|saml|2018-01-08|55  |55  |
|saml|2018-01-05|46  |101 |
|saml|2018-01-01|10  |111 |
|tony|2018-01-07|50  |50  |
|tony|2018-01-04|29  |79  |
|tony|2018-01-02|15  |94  |
|saml|2018-02-03|23  |23  |
|mart|2018-04-13|94  |94  |
|mart|2018-04-11|75  |169 |
|mart|2018-04-09|68  |237 |
|mart|2018-04-08|62  |299 |
|saml|2018-04-06|42  |42  |
|neil|2018-05-10|12  |12  |
|neil|2018-06-12|80  |80  |
+----+----------+----+----+

注意:可以使用partition by + order by 组合来代替distribute by+sort by组合

select name, orderdate, cost,
sum(cost) over (partition by name, month(orderdate) order by orderdate desc)
from t_order;

注意:也可以在窗口函数中,只写排序窗口大小是全表记录。
实际上就是把整个表当作一个组了. 也是有这个需求的,毕竟不开窗不能看明细,然而又想当成一个组

select *, sum(cost) over (order by orderdate desc)
from t_order;+----+----------+----+---+
|name|orderdate |cost|c1 |
+----+----------+----+---+
|neil|2018-06-12|80  |80 |
|neil|2018-05-10|12  |92 |
|mart|2018-04-13|94  |186|
|mart|2018-04-11|75  |261|
|mart|2018-04-09|68  |329|
|mart|2018-04-08|62  |391|
|saml|2018-04-06|42  |433|
|saml|2018-02-03|23  |456|
|saml|2018-01-08|55  |511|
|tony|2018-01-07|50  |561|
|saml|2018-01-05|46  |607|
|tony|2018-01-04|29  |636|
|tony|2018-01-02|15  |651|
|saml|2018-01-01|10  |661|
|    |NULL      |NULL|661|
+----+----------+----+---+

Window子句

如果要对窗口的结果做更细粒度的划分,那么就使用window子句,常见的有下面几个

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

一般window子句都是rows开头

案例:

select name,orderdate,cost,sum(cost) over ()                                                                                       as sample1,--所有行相加sum(cost) over (partition by name)                                                                      as sample2,-- 按name分组,组内数据相加sum(cost) over (partition by name order by orderdate)                                                   as sample3,-- 按name分组,组内数据累加sum(cost)over (partition by name order by orderdate rows between UNBOUNDED PRECEDING and current row )       as sample4,-- 与sample3一样,由起点到当前行的聚合sum(cost)over (partition by name order by orderdate rows between 1 PRECEDING and current row)                as sample5, -- 当前行和前面一行做聚合sum(cost)over (partition by name order by orderdate rows between 1 PRECEDING AND 1 FOLLOWING )               as sample6,-- 当前行和前边一行及后面一行sum(cost)over (partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING )       as sample7 -- 当前行及后面所有行from t_order;
+----+----------+----+-------+-------+-------+-------+-------+-------+-------+
|name|orderdate |cost|sample1|sample2|sample3|sample4|sample5|sample6|sample7|
+----+----------+----+-------+-------+-------+-------+-------+-------+-------+
|    |NULL      |NULL|661    |NULL   |NULL   |NULL   |NULL   |NULL   |NULL   |
|mart|2018-04-08|62  |661    |299    |62     |62     |62     |130    |299    |
|mart|2018-04-09|68  |661    |299    |130    |130    |130    |205    |237    |
|mart|2018-04-11|75  |661    |299    |205    |205    |143    |237    |169    |
|mart|2018-04-13|94  |661    |299    |299    |299    |169    |169    |94     |
|neil|2018-05-10|12  |661    |92     |12     |12     |12     |92     |92     |
|neil|2018-06-12|80  |661    |92     |92     |92     |92     |92     |80     |
|saml|2018-01-01|10  |661    |176    |10     |10     |10     |56     |176    |
|saml|2018-01-05|46  |661    |176    |56     |56     |56     |111    |166    |
|saml|2018-01-08|55  |661    |176    |111    |111    |101    |124    |120    |
|saml|2018-02-03|23  |661    |176    |134    |134    |78     |120    |65     |
|saml|2018-04-06|42  |661    |176    |176    |176    |65     |65     |42     |
|tony|2018-01-02|15  |661    |94     |15     |15     |15     |44     |94     |
|tony|2018-01-04|29  |661    |94     |44     |44     |44     |94     |79     |
|tony|2018-01-07|50  |661    |94     |94     |94     |79     |79     |50     |
+----+----------+----+-------+-------+-------+-------+-------+-------+-------+

需求:查看顾客到目前为止的购买总额

select name,orderdate,cost,sum(cost)over (partition by name order by orderdate rows between unbounded preceding and current row ) as allCount
from t_order;
+----+----------+----+--------+
|name|orderdate |cost|allcount|
+----+----------+----+--------+
|    |NULL      |NULL|NULL    |
|mart|2018-04-08|62  |62      |
|mart|2018-04-09|68  |130     |
|mart|2018-04-11|75  |205     |
|mart|2018-04-13|94  |299     |
|neil|2018-05-10|12  |12      |
|neil|2018-06-12|80  |92      |
|saml|2018-01-01|10  |10      |
|saml|2018-01-05|46  |56      |
|saml|2018-01-08|55  |111     |
|saml|2018-02-03|23  |134     |
|saml|2018-04-06|42  |176     |
|tony|2018-01-02|15  |15      |
|tony|2018-01-04|29  |44      |
|tony|2018-01-07|50  |94      |
+----+----------+----+--------+

需求:求每个顾客最近三次的消费总额

select name,orderdate,cost,sum(cost)over (partition by name order by orderdate rows between 2 preceding  and current row ) as allCount
from t_order;
+----+----------+----+--------+
|name|orderdate |cost|allcount|
+----+----------+----+--------+
|    |NULL      |NULL|NULL    |
|mart|2018-04-08|62  |62      |
|mart|2018-04-09|68  |130     |
|mart|2018-04-11|75  |205     |
|mart|2018-04-13|94  |237     |
|neil|2018-05-10|12  |12      |
|neil|2018-06-12|80  |92      |
|saml|2018-01-01|10  |10      |
|saml|2018-01-05|46  |56      |
|saml|2018-01-08|55  |111     |
|saml|2018-02-03|23  |124     |
|saml|2018-04-06|42  |120     |
|tony|2018-01-02|15  |15      |
|tony|2018-01-04|29  |44      |
|tony|2018-01-07|50  |94      |
+----+----------+----+--------+

总结

  • 窗口函数的意义在于明细+聚合,二者缺一不可
  • 理解分组的大小雨窗口大小的关系
  • window子句是比Partition by更细粒度的统计
  • 如果既要明细又要聚合,就要用到开窗函数

hive窗口函数入门相关推荐

  1. Hive窗口函数小结

    文章目录 一.窗口函数作用 1.1.测试数据 1.2.应用场景 二.窗口函数概念 2.1.语法结构 2.2.分析函数 2.3.over函数的参数 三.窗口函数入门 3.1.over(partition ...

  2. 大数据技术-hive窗口函数详解

    有不少同学一听这个标题,hive窗口函数是什么鬼?没听说过还有窗口函数这个东西啊,其实它的用处可大了,下面听小千慢慢道来. hive窗口函数 窗口函数指定了函数工作的数据窗口大小(当前行的上下多少行) ...

  3. mysql窗口函数_MySQL8.0窗口函数入门实践及总结

    前言 MySQL8.0之前,做数据排名统计等相当痛苦,因为没有像Oracle.SQL SERVER .PostgreSQL等其他数据库那样的窗口函数.但随着MySQL8.0中新增了窗口函数之后,针对这 ...

  4. hadoop hive hbase 入门学习 (二)

    hadoop 自学系列                hadoop hive hbase 入门学习 (一) hadoop安装.hdfs学习及mapreduce学习 hadoop 软件下载 (hadoo ...

  5. HiveQL学习笔记(四):Hive窗口函数

    本系列是本人对Hive的学习进行一个整理,主要包括以下内容: 1.HiveQL学习笔记(一):Hive安装及Hadoop,Hive原理简介 2.HiveQL学习笔记(二):Hive基础语法与常用函数 ...

  6. hive窗口函数使用

    hive窗口函数的使用 前言 一.hive窗口函数语法 1.over()窗口函数的语法结构 1.1.over()函数中的三个函数讲解 2.常与over()一起使用的分析函数 2.1.聚合类 2.2.排 ...

  7. Hive从入门到放弃——HiveQL表级别DDL设计的艺术性(五)

    HiveQL数据库中的表DDL操作   博客Hive从入门到放弃--HiveQL数据库级别DDL设计的艺术性(四)聊完了数据库的基本操作,我们再来聊聊Hive内表的操作. 创建表   官方推荐建表的结 ...

  8. Hive 窗口函数 实现原理

    Hive 窗口函数 实现原理 hive中窗口函数的实现,主要是借助于一个叫做 Windowing Table Function 的Partitioned Table Function Partitio ...

  9. hive 窗口函数(持续更新)

    hive窗口函数语法 avg().sum().max().min()等是分析函数,而over()才是窗口函数,下面我们来看看over()窗口函数的语法结构.及常与over()一起使用的分析函数: 1. ...

最新文章

  1. php大号字体代码,支持中文字母数字、自定义字体php验证码代码
  2. tp5 上传文件乱码问题
  3. JavaEE Tutorials (17) - Java消息服务示例
  4. Java EE 7中的WebSocket客户端API
  5. Pytorch 加载部分预训练模型并冻结某些层
  6. oracle事务提交前更新机制,Oracle 事务机制 批量添加,修改,更新
  7. 如何才能做到网站高并发访问?
  8. 失业几个月找不到工作是一种怎样的体验?
  9. 新增了归并数组的方法!
  10. 多校3 1008 Solve this interesting problem
  11. 010 Editor v8.0.1(32 - bit) 算法逆向分析、注册机编写
  12. mugen linux主程序,mugen主程序win版下载
  13. bp神经网络优化算法对比,bp神经网络的优化算法
  14. ABBYY FineReader OCR图片文字识别软件安装应用
  15. 冒犯有时是必要的:如何开启一段亲密关系?
  16. 【kubernetes】k8s的job和cronjob详细说明【job、cronjob(cj)、descheduler(pod均衡)】
  17. worldpress 添加网站关键词和描述
  18. 计算机毕业设计Java-ssmC语言教学辅导网站源码+系统+数据库+lw文档
  19. 商业图表案例3-CO2排放量与人均GDP
  20. 治疗脚气、脚臭偏方!

热门文章

  1. tensorflow2.0 图像处理项目_UCOSIII移植——STM32F769I 图像处理能力评测之五
  2. 一加6屏幕测试代码_一加 7的普通版与Pro/参数对比
  3. linux shell 后台执行脚本的方法 脚本后台运行 后台运行程
  4. Eclipse中查看JDK类库的源代码
  5. HTML表单效果图,html-图片/表格/表单
  6. Vue 动画 过渡的类名
  7. oracle sql 导入mysql数据库备份_使用PL/SQL连接oracle数据库,并将数据进行导出备份和导入恢复...
  8. css手型指针_前端基础面试题(HTML+CSS部分)
  9. linux unix域socket_从文件描述符到Socket
  10. linux 22 口令自动传马,近期用到的linux命令