MySQL中的窗口函数
从version 8.0开始,MySQL支持在查询中使用窗口函数。这篇文章是对一篇英文资料的不完全翻译,加上自己的一些理解。如果有兴趣可以去看看原文章。文中的示例用到的建表语句和插值语句如下:
CREATE TABLE sales(sales_employee VARCHAR(50) NOT NULL,fiscal_year INT NOT NULL,sale DECIMAL(14,2) NOT NULL,PRIMARY KEY(sales_employee,fiscal_year)
);INSERT INTO sales(sales_employee,fiscal_year,sale)
VALUES('Bob',2016,100),('Bob',2017,150),('Bob',2018,200),('Alice',2016,150),('Alice',2017,100),('Alice',2018,200),('John',2016,200),('John',2017,150),('John',2018,250);
先看一个例子:
SELECT fiscal_year, sales_employee,sale,SUM(sale) OVER (PARTITION BY fiscal_year) total_sales
FROMsales;
执行后得到的结果如下:
+-------------+----------------+--------+-------------+
| fiscal_year | sales_employee | sale | total_sales |
+-------------+----------------+--------+-------------+
| 2016 | Alice | 150.00 | 450.00 |
| 2016 | Bob | 100.00 | 450.00 |
| 2016 | John | 200.00 | 450.00 |
| 2017 | Alice | 100.00 | 400.00 |
| 2017 | Bob | 150.00 | 400.00 |
| 2017 | John | 150.00 | 400.00 |
| 2018 | Alice | 200.00 | 650.00 |
| 2018 | Bob | 200.00 | 650.00 |
| 2018 | John | 250.00 | 650.00 |
+-------------+----------------+--------+-------------+
9 rows in set (0.00 sec)
这里,sum()函数充当了窗口函数,得到了根据fiscal_year计算出的sale的总和total_sales列,但是又不像它作为聚合函数使用时一样,这里的结果保留了每一行的信息。
原因就在于窗口函数的执行顺序(逻辑上的)是在FROM,JOIN,WHERE,GROUP BY,HAVING之后,在ORDER BY,LIMIT,SELECT DISTINCT之前。它执行时GROUP BY的聚合过程已经完成了,所以不会再产生数据聚合。
窗口函数的语法
窗口函数的语法是
window_function_name(expression) OVER ([partition_defintion][order_definition][frame_definition])
先指定作为窗口函数的函数名,然后是OVER(…),就算OVER里面没有内容,括号也需要保留。
窗口函数的一个概念是当前行,当前行属于某个窗口,窗口由“[partition_defintion]”,“[order_definition]”,“[frame_definition]“确定。
- partition_defintion
翻译过来应该是分区,语法是"PARTITION BY < expression>[{,< expression>…}]",它会根据单个或者多个表达式的计算结果来分区(列名也是一种表达式,它的结果就是列名本身)。在前面的例子中,结果中的每一行都有自己的分区,total_sales列的值就是它所属的分区里面的sum(sale)的结果。 - frame_definition
这里先讲frame_definition,可能应该是叫帧吧。它的作用是在分区里面再进一步细分窗口。语法是"frame_unit {< frame_start>|< frame_between>}",frame_unit有两种,分别是ROWS和RANGE,由ROWS定义的frame是由开始和结束位置的行确定的,由RANGE定义的frame由在某个值区间的行确定。
如果只指定了frame的开始位置,那么结束位置就默认为当前行。frame_start有三种:
- UNBOUNDED PRECEDING: 区间的第一行
- N PRECEDING: 当前行之前的N行,N可以是数字,也可以是一个能计算出数字的表达式
- CURRENT ROW: 当前行
frame_between的可以取的值如下:
- frame_start:如前面所列
- UNBOUNDED FOLLOWING:区间的最后一行
- N FOLLOWING:当前行之后的N行,N可以是数字,也可以是一个能计算出数字的表达式
如果没显式指定frame的话,MySQL会认为frame是“ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING”
这个有点复杂,看个例子:
SELECT fiscal_year, sales_employee,sale,SUM(sale) OVER (PARTITION BY sales_employee ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) total_sales
FROMsales;
执行结果如下:
+-------------+----------------+--------+-------------+
| fiscal_year | sales_employee | sale | total_sales |
+-------------+----------------+--------+-------------+
| 2016 | Alice | 150.00 | 150.00 |
| 2017 | Alice | 100.00 | 250.00 |
| 2018 | Alice | 200.00 | 450.00 |
| 2016 | Bob | 100.00 | 100.00 |
| 2017 | Bob | 150.00 | 250.00 |
| 2018 | Bob | 200.00 | 450.00 |
| 2016 | John | 200.00 | 200.00 |
| 2017 | John | 150.00 | 350.00 |
| 2018 | John | 250.00 | 600.00 |
+-------------+----------------+--------+-------------+
9 rows in set (0.00 sec)
第一行所在的区间是sales_employee为Alice的区间,所在的帧是区间第一行到当前行,只有一行,total_sales为150;第二行所在的区间是sales_employee为Alice的区间,所在的帧是区间第一行到当前行,有两行,total_sales为150+100=250;第一行所在的区间是sales_employee为Alice的区间,所在的帧是区间第一行到当前行,有三行,total_sales为150+100+200=450。
- order_definition
定义了分区内的行的排列顺序,语法是“ORDER BY < expression> [ASC|DESC], [{,< expression>…}]”。没什么好讲的。
MySQL中的窗口函数相关推荐
- mysql中还有窗口函数?这是什么东西?
什么是窗口函数? 在mysql8.0的版本中,新增了一个窗口函数,用他可以实现很多新的查询方式.窗口函数类似于sun().count()那样的集合函数,但它并不会将多行查询结果合并为一行,而是将结果放 ...
- mysql over rank_sql - MySQL中的Rank函数
sql - MySQL中的Rank函数 我需要找出客户的排名. 在这里,我为我的要求添加了相应的ANSI标准SQL查询. 请帮我转换为MySQL. SELECT RANK() OVER (PARTIT ...
- MySQL中的sum函数用法实例详解
今天分享一下mysql中的sum函数使用.该函数已经成为大家操作mysql数据库中时常用到的一个函数,这个函数统计满足条件行中指定列的和,想必肯定大家都知道了,本身就没什么讲头了,这篇文章主要是通过几 ...
- 「数据分析」Sqlserver中的窗口函数的精彩应用之数据差距与数据岛(含答案)...
上一篇介绍过数据差距与数据岛的背景,这里不再赘述,请翻阅上一文.此篇在Sqlserver上给大家演示1000万条记录的计算性能. 测试电脑软硬件说明 一般般的笔记本电脑,2017年7月,价格:4500 ...
- sql查询三级菜单分类_SQL面试50题——思路解答与分类整理(中)窗口函数与子查询...
让我们每天都进步一点点 题目快速查找索引 阅读指南 上篇:SQL面试50题--思路解答与分类整理(上)聚合函数与表连接 [第一部分]聚合函数(sum/avg/count/min/max) [第二部分] ...
- MySQL 8.0窗口函数
团队介绍 网易乐得DBA组,负责网易乐得电商.网易邮箱.网易技术部数据库日常运维,负责数据库私有云平台的开发和维护,负责数据库及数据库中间件Cetus的开发和测试等等. 一.窗口函数的使用场景 作为I ...
- Mysql 不使用窗口函数实现分组排序 rank 别名问题
Mysql 不使用窗口函数实现分组排序 变量 定义和修改 方法1 set @变量名:=值: set @name="bob"; set @name="jojo"; ...
- MySQL中查询中位数?
导读 计算中位数可能是小学的内容,然而在数据库查询中实现却并不是一件容易的事.我们今天就来看看都有哪些方法可以实现. 注:本文所用MySQL版本无限制,所列题目均来源于LeetCode. LeetCo ...
- SQL 中的窗口函数
SQL 中的窗口函数(Window Functions)是一种特殊的函数,它可以在查询结果的某个区间内执行计算,而不仅仅是对单个行进行计算. 以下是一些常用的窗口函数: 1.ROW_NUMBER() ...
- MySql中@符号的使用
MySql中@符号的使用 @符号的作用 @后接变量名,用以定义一个变量,该变量的有效期为语句级,即再一次执行中始终有效,基本示例如下: -- 由于通常情况下=被认为是等于比较运算符,因此赋值运算符一般 ...
最新文章
- Java项目:OA办公自动化系统设计和实现(java+springboot+freemarker+mysql+maven+mybatis+jpa)
- 模板方法模式与策略模式的区别
- bal插口_EBS R12各模块接口表大全
- Hadoop组件基本操作
- JS原生封装动画函数
- [剑指offer]面试题第[43]题[Leetcode][第233题][JAVA][1~n整数中1出现的次数][找规律][递归]
- axis2开发webservice之编写Axis2模块(Module)
- 系统软键盘Android在外接物理键盘时,如何强制调用系统软键盘?
- ThreadPoolExecutor执行过程分析
- 【SimpleITK】Resampling重采样
- 利用循环打印正方形和长方形
- 细数处女座的101个特质
- codeforces1467E. Distinctive Roots in a Tree
- pr cpu100%_PR插件NewBlueFX Titler Pro6.0安装教程
- 最后1天!生信入门转录组和可视化学习捷径
- 用html css JavaScript写一个功能全面的王者荣耀轮播图 (仿淘宝京东轮播图)通俗易懂
- NetHunter-Rootless:安卓手机免Root安装Kali NetHunter
- 西门子et200 分布式i/o_西门子S7-1500H冗余系统硬件及网络结构
- cesium建筑物3DTile单体化(cesium篇.24)
- 【搜集+亲测】无法注册Flash Player的Activex控件最终解决方法(亲测,WIN7 64位系统)