神奇的 SQL ,高级处理之 Window Functions → 打破我们的局限!
开心一刻
今天儿子跟老婆聊天
儿子:妈妈,我为什么没有两个爸爸呀
老婆:每个人都只有一个爸爸呀,你看谁有两个爸爸了
儿子一脸真诚的看着老婆:那你为什么就有两个爸爸呢
老婆一脸疑惑的望向儿子:我哪有两个爸爸了?
儿子有点不服气,温柔地说道:你管爷爷叫爸爸,你管姥爷还叫爸爸,这不就是两个爸爸吗
老婆轻声解释道:虽然我管他们两个都叫爸爸,但是姥爷才是我的爸爸,爷爷是爸爸的爸爸,是我公公,明白了吗
儿子两眼朝天上看了下,若有所思道:公公不是太监吗
老婆惊讶道:什么太监呀,我说的公公和你说的公公不是一回事,你这一天天的脑子里都想什么呢
儿子生气道:你不用解释了,待会我就告诉奶奶,你说爷爷是太监
什么是窗口函数
Window Function 也称为 OLAP(Online Analytical Processing)函数
对数据库数据进行实时分析处理,例如市场分析、财务报表等,是标准的 SQL 功能
中文翻译过来,叫 窗口函数 ,或者 开窗函数 ,在 Oracle 中也称 分析函数
与 聚合函数 一样,也是对集合进行聚合计算,但和 聚合函数 又不一样,使用 聚合函数 时,每组只返回一个值,但 开窗函数 可以为组中的每一行返回一个值
你们懂我说的意思吧
现在不懂也没关系哈,继续往下看,看完之后你肯定就懂了
支持情况
既然 窗口函数 是 标准 SQL 功能 ,那关系型数据库应该都支持吧
Oracle 11g 、 SQL Server 2008 、 DB2 9.7 、 PostgreSQL 8.4 都支持窗口函数
但 MySQL 从 8 开始才支持, MySQL5.7 及之前的版本不支持 窗口函数
关于对标准 SQL 的支持以及支持程度,还得看各个数据库厂商,有的支持的早、支持的全,也有的支持的晚、支持的少
但随着时间的推移,标准 SQL 终将能在所有的 DBMS 中使用
窗口函数的语法
基本语法如下
看着很简单,但却很陌生,我们将其进行拆分下
1、 窗口函数 ,命名一般是见名知意,表明这个函数要实现的功能
2、 OVER 子句, OVER 是约定好的固定写法,其内容是规则的指定,告诉 窗口函数 以怎样的规则去实现功能
PARTITION BY 类似 GROUP BY ,指定分组规则
ORDER BY 就跟我们平时使用的 ORDER BY 一样,指定排序规则
看完这个语法介绍,我相信大家还是很懵,我非常理解大家
但先别慌,结合案例来看,慢慢就懂了
能够作为窗口函数使用的函数分两种
1、专用窗口函数,如: RANK 、 ROW_NUMBER 、 DENSE_RANK 等等
2、能够作为窗口函数的聚合函数,如: SUM 、 AVG 、 COUNT 、 MAX 、 MIN
后续的案例演示我们基于 MySQL8.0.30 ,初始表 tbl_ware 及数据如下


CREATE TABLE `tbl_ware` (
`ware_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '商品id',
`ware_name` VARCHAR(100) NOT NULL COMMENT '商品名称',
`ware_category` VARCHAR(100) NOT NULL COMMENT '商品类别',
`sale_unit_price` INT COMMENT '销售单价',
`purchase_unit_price` INT COMMENT '进货单价',
`registration_date` DATE COMMENT '等级日期',
PRIMARY KEY (`ware_id`) USING BTREE
) ENGINE=InnoDB COMMENT='产品'; INSERT INTO tbl_ware VALUES
(1,'T恤衫','衣服',100, 50,'2023-12-15'),
(2,'打孔器','办公用品',25, 10,'2023-12-15'),
(3,'运动T恤','衣服',150, 50,'2023-12-15'),
(4,'菜刀','厨房用具',75, 30,'2023-12-15'),
(5,'高压锅','厨房用具',600, 200,'2023-12-15'),
(6,'叉子','厨房用具',7, 3,'2023-12-15'),
(7,'菜板','厨房用具',98, 30,'2023-12-15'),
(8,'圆珠笔','办公用品',5, 2,'2023-12-15');
专用窗口函数
这些函数是标准 SQL 定义的 OLAP 专用函数,通过函数名很容易看出其 OLAP 的用途
RANK
从名字可知,该函数用来排名、排序
1、假设我们对 tbl_ware 按售价从高到低进行排名, SQL 该如何写
相信大家很容易就写出来了: SELECT * FROM tbl_ware ORDER BY sale_unit_price DESC;
用 RANK 也能实现: SELECT *, RANK() OVER(ORDER BY sale_unit_price DESC) AS ranking FROM tbl_ware;
2、假设我们对 tbl_ware 按类别进行分组,然后组内按售价从高到低进行排名, SQL 又该如何写
有小伙伴一看到分组二字,第一反应肯定想到了 GROUP BY ,不只是你们,我也是一样的
但 GROUP BY 往往结合 聚合函数 使用,分组后每组只能得到一个值,显然满足不了需求
但 RANK 可以: SELECT *, RANK() OVER(PARTITION BY ware_category ORDER BY sale_unit_price DESC) AS ranking FROM tbl_ware;
PARTITION BY 对表的横向进行分组,类似 GROUP BY ,但不具备聚合功能
ORDER BY 则决定了纵向排序的规则,与 SELECT 子句末尾的 ORDER BY 子句完全相同
通过 PARTITION BY 分组后的记录集合称为“窗口”,代表“范围”。这也是 窗口函数 名称的由来
DENSE_RANK
一看名字就知道跟 RANK 有关系,为了对比它俩的区别,需要补充几条数据


INSERT INTO tbl_ware VALUES
(9,'带帽卫衣','衣服', 150, 90, '2023-12-15'),
(10,'砍骨刀','厨房用具', 150, 69, '2023-12-15');
RANK 排序时,如果存在相同位次的记录,会跳过之后的位次,如: 1,2,2,2,5 , 3,4 被跳过了
DENSE_RANK 排序时,如果存在相同位次的记录,则不会跳过之后的位次,如: 1,2,2,2,3,4
ROW_NUMBER
获取行数或者行号
如果我们想按售价从高到低排序后,获取每一行的行号, SQL 可写成: SELECT *, ROW_NUMBER() OVER(ORDER BY sale_unit_price DESC) AS row_num FROM tbl_ware;
如果再加上一个分组: SELECT *, ROW_NUMBER() OVER(PARTITION BY ware_category ORDER BY sale_unit_price DESC) AS row_num FROM tbl_ware;
此刻大家应该想起点什么了
分组取前N条,是不是很适合用这种方式实现?
我都跟你们实现好了:MySQL 分组排序后 → 如何取前N条或倒数N条
还有其他的 专用窗口函数 就不一一做介绍了,大家可以去各个数据库的官网进行查阅
聚合函数的窗口化使用
所有的 聚合函数 都能用作窗口函数,其语法和 专用窗口函数 完全相同
作为窗口化使用后, 聚合函数 实现的效果就发生了很大的变化,我们来看具体案例
SUM
作为 聚合函数 , SUM 的作用想必大家都很清楚了
但是窗口化之后了,我们来看看效果
发现什么了?
并不是一个单独的汇总值,而是逐行汇总,是不是有点意思?
如果再加上分组
分组后,对每一组进行逐行汇总
AVG
类比 SUM ,我们直接看分组的情况
分组后,对每一组的每一行求历史平均值
其他 聚合函数 的窗口化就不一一演示了,相信大家也都明白了
窗口函数的适用范围
通过上述的几个案例,相信大家对这个问题已经有了一个大致的答案
窗口函数 只能在 SELECT 子句中使用,不能在 WHERE 子句或者 GROUP BY 子句中使用,为什么了?
因为 窗口函数 是对 WHERE 子句或者 GROUP BY 子句处理后的“结果”进行的逐行操作
我们换个角度来看, 窗口函数 是不会改变结果行数的,而 WHERE 是会改变结果行数的,那把 窗口函数 放到 WHERE 子句的意义何在?
所以一不做二不休,直接在语法上做了这样的限制: 窗口函数 只能在 SELECT 子句中使用
总结
1、 窗口函数 是标准的 SQL 功能,而非特定数据库的功能
SQL 功能的落地还得依赖各个数据库厂商
提供了标准,数据库厂商不一定实现,或者说暂时不实现
2、 窗口函数 与 聚合函数 并非矛盾,二者是互补关系
3、之所以对 窗口函数 这么陌生,主要是我们使用太少,但是其在报表分析方面还是很有作用的
4、 窗口函数 的使用范围很有限,你可以随意使用,报语法错误了再调整呗
参考
《SQL 基础教程》
神奇的 SQL ,高级处理之 Window Functions → 打破我们的局限!的更多相关文章
- Oracle SQL高级编程——分析函数(窗口函数)全面讲解
Oracle SQL高级编程--分析函数(窗口函数)全面讲解 注:本文来源于:<Oracle SQL高级编程--分析函数(窗口函数)全面讲解> 概述 分析函数是以一定的方法在一个与当前行相 ...
- MySQL 8.0.2: Introducing Window Functions
July 18, 2017MySQL, SQLDag Wanvik MySQL 8.0.2 introduces SQL window functions, or analytic functions ...
- oracle sql 高级编程 历史笔记整理
20130909 周一 oracle sql 开发指南 第7章 高级查询 1.层次化查询select level,ttt.*,sys_connect_by_path(ttt.col1,',') fro ...
- SQL 高级查询(层次化查询,递归)
SQL 高级查询 前面我们写了一下 SQL 的极简入门,今天来说点高级查询.没看到的朋友可以点击下面链接查看. 1 小时 SQL 极速入门(一) 1 小时 SQL 极速入门(二) 1 小时 SQL 极 ...
- SQL高级查询技巧
SQL高级查询技巧 1.UNION,EXCEPT,INTERSECT运算符 A,UNION 运算符 UNION 运算符通过组合其他两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重 ...
- 13Microsoft SQL Server SQL 高级事务,锁,游标,分区
Microsoft SQL Server SQL高级事务,锁,游标,分区 通过采用事务和锁机制,解决了数据库系统的并发性问题. 9.1数据库事务 (1)BEGIN TRANSACTION语句定义事务的 ...
- 一些SQL高级函数
一些SQL高级函数 Posted on 2010-08-08 21:34 moss_tan_jun 阅读(311) 评论(0) 编辑 收藏 长度与分析用 datalength(Char_expr) 返 ...
- 神奇的 SQL 之谓词 → 难理解的 EXISTS
前言 开心一刻 我要飞的更高,飞的更高,啊! 谓词 SQL 中的谓词指的是:返回值是逻辑值的函数.我们知道函数的返回值有可能是数字.字符串或者日期等等,但谓词的返回值全部是逻辑值(TRUE/FALSE ...
- oracle学习笔记(十七) PL/SQL高级应用
PL/SQL高级应用 动态SQL 在PL/SQL中,不能直接执行DDL(create,alter,drop),得使用动态SQL,当然,除了DDL,动态SQL也可以执行DML(select,insert ...
- 神奇的 SQL 之 联表细节 → MySQL JOIN 的执行过程(二)
开心一刻 一头母牛在吃草,突然一头公牛从远处狂奔而来说:“快跑啊!!楼主来了!” 母牛说:“楼主来了关我屁事啊?” 公牛急忙说:“楼主吹牛逼呀!” 母牛大惊,拔腿就跑,边跑边问:“你是公牛你怕什么啊? ...
随机推荐
- Nomad 系列-快速上手
系列文章 Nomad 系列文章 Nomad 重要术语 Nomad 安装设置相关术语 agent - 代理.Agent 是在 Server(服务器) 或 Client(客户端) 模式下运行的 Nomad ...
- 我在前端写Java SpringBoot项目
前言 玩归玩,闹归闹,别拿 C端 开玩笑! 这里不推荐大家把Node服务作为C端服务,毕竟它是单线程多任务 机制. 这一特性是 Javascript 语言设计之初,就决定了它的使命 - Java &g ...
- CF1352D
题目简化和分析: 这题可以直接按照题意进行模拟,当然有些细节需要注意. 翻译的不足:这里的回合指任意一个人吃掉都算,而不是双方一个回合,最后一个人即使不满足也算一个回合. 我们可以采用两个指针模拟两个 ...
- STM32 + ESP32(AT固件 MQTT协议) + MQTTX(桌面终端) + (EMQX消息服务器)
翻出老物件,搭建一个简单的 IOT 开发环境,也算是废物利用了 ,接下来加传感器.1. STM32 采集数据: RTOS. 资源相对比较丰富,可以根据项目需求定制.2. ESP32 ...
- 虹科案例 | 虹科Domo商业智能,助力保险公司逃离繁杂数据池!
金融行业的发展充满着不确定性,一个具备强大承保能力和精算专业知识的资金池,对于身处该领域的公司和个人都是十分必要的. 在全国城市联盟(NLC)的协助下成立的NCL Mutual会员制互助保险公司,为各 ...
- 动态规划的状态设计 | bot 讲课の补题
sto james1badcreeper orz. 好厉害的题,但是怎么有人补了三天才补完呢? CF1810G The Maximum Prefix 线性 dp,怎么有 bot 说题目难度在 *240 ...
- PTA乙级1039(C++)散列表解法
题目 1039 到底买不买 小红想买些珠子做一串自己喜欢的珠串.卖珠子的摊主有很多串五颜六色的珠串,但是不肯把任何一串拆散了卖. 于是小红要你帮忙判断一下,某串珠子里是否包含了全部自己想要的珠子?如 ...
- JavaScript:垃圾收集机制
JavaScript具有自动垃圾收集机制.也就是说,执行环境会负责管理代码执行过程中使用的内存.开发人员不必关心内存分配和回收问题. 垃圾收集机制的原理:找到不再继续使用的变量,然后进行释放其占用的内 ...
- Gson替换掉多漏洞的FastJson
添加依赖: <!-- gson --> <dependency> <groupId>com.google.code.gson</groupId> < ...
- 关于XML的总结——Schema和DTD(转)
XML DTD(XML的文档类型定义)是近几年来XML技术领域所使用的最广泛的一种模式.但是,由于XML DTD并不能完全满足XML自动化处理的要求,例如不能很好实现应用程序不同模块间的相互协调,缺乏 ...