当前位置: 首页 > news >正文

窗口函数的概念

SQL的世界中,窗口函数(也称为开窗函数)可以算是一把高效数据分析的利器。对于数据工程师或者相关人员来说,掌握窗口函数是迈向高效处理数据的重要一步。举个例子:现数据库中有如下一张销量表数据,展示了一年中每个月份的销售额:

图片
如何快速用SQL求出每个月的销量排名、季度累计销量、年度累计销量、同比和环比增长率等?这就得靠咱们今天的主角:窗口函数。

一、概念

窗口函数是在 SQL 查询中对一组相关联的记录进行计算而返回一个值的函数。与普通的聚合函数(如SUM, AVG等)类似,但有一个关键区别:窗口函数不会将多行合并成单行输出,而是保留原始的行数,并在每行上附加计算结果。这意味着你可以在同一行中同时看到原始数据和聚合结果。

窗口函数的语法结构通常为:

函数名() OVER ( [partition by] order by() )
其中,能够作为窗口函数的有,如 SUM、AVG、COUNT、MIN、MAX 这样的聚合函数,还有RANK、DENSE_RANK、ROW_NUMBER这样的专用窗口函数;OVER 子句定义了窗口的范围和排序规则,它的内部有partition by和order by。“partition by” 将数据集划分成多个分区,每个分区独立计算,其可以省略,即不划区域,针对整个数据集;order by则用于指定分区内的排序顺序。这样解释可能有点抽象,我们一起来看具体的例子。

二、排序窗口函数

能作为窗口函数使用的有很多,先从简单的排序函数开始看起,其主要用于对数据赋予相应的序号(或者说排名值),特别是在需要对数据进行分层分组、组内排序和比较的场景中。常见的排序窗口函数有3个:ROW_NUMBER()、RANK()和DENSE_RANK()。

1.ROW_NUMBER()

ROW_NUMBER() 函数为分区内的每一行赋予一个唯一的连续整数编号。这个编号从 1 开始,按照指定的排序规则依次递增。

例如,在商品销售数据表中,我们可以使用如下SQL为商品按照销售量从高到低进行排名编号:

SELECT sales_date,
quarter,
sales_volume,
– 销量排名(按销量降序)
ROW_NUMBER() OVER (ORDER BY sales_volume DESC) AS sales_rank
FROM dbo.test;
结果如下:

图片
得到了一年中12个月的销量排名,如果想还是按原来的1-12月进行排序,可以在最后再加一个ORDER BY sales_date。看到上面的SQL中是没有partition by的,即没有进行分区,针对的是所有时间段的数据,如果我们想按季度进行分区(对应的是组内排序场景),获取到每个季度中各月的排名,可以写成:

SELECT sales_date,
quarter,
sales_volume,
– 销量排名(按销量降序)
ROW_NUMBER() OVER (ORDER BY sales_volume DESC) AS sales_rank,
– 销量季度排名
ROW_NUMBER() OVER (PARTITION BY quarter ORDER BY sales_volume DESC) AS quarter_rank
FROM dbo.test
ORDER BY sales_date
图片
即使有销量数据相同的情况,ROW_NUMBER() 也会为它们分配不同的序号,确保每个排名值的唯一性。

2.RANK()

RANK() 函数与 ROW_NUMBER() 类似,也是用于对数据进行排名。但是,RANK() 函数在遇到相同值的行时,会赋予它们相同的排名值,并且后续行的排名会跳跃。简单记忆就是在班级中的成绩排名,如果有两个人100分,他们并列第一,后面的99分是第3名。

用法和上面的ROW_NUMBER()差不多,例如:

SELECT sales_date,
quarter,
sales_volume,
– 销量排名(按销量降序)
RANK() OVER (ORDER BY sales_volume DESC) AS sales_rank
FROM dbo.test
图片
大家可以看到2024年2月和3月的数据相同时,rank()的结果都是8,而后的是10。这种排名方式常用在一些需要突出显示相同排名数据的场景中,比如在比赛成绩排名中,若多个选手得分相同,则他们共享同一个名次,而后续选手的名次则相应顺延。

3.DENSE_RANK()

还有第3个排名函数DENSE_RANK() ,与 RANK() 不同的是,DENSE_RANK() 在遇到相同值时,赋予它们相同的排名,但后续行的排名不会跳跃。也就是说,排名值是连续的。例如:

图片

对于这3种排序函数,用法上相似,只是针对相同值时生成的序号有所不同,大家根据实际的情况选择合适的即可。

本来还准备写关于作为窗口函数使用的聚合函数,由于篇幅限制,所以另写一篇吧。这里给大家做个总结:

窗口函数可以类比前面学的聚合函数,但是光靠聚合函数,有时候不好解决问题。因为聚合函数的特定是“汇总”统计,本来有十几行数据,sum一下,只得到了一个总的值,将原本N行数据进行了“压缩”,这种聚合有时会“丢失”细节信息。所以后来为了方便处理一些数据分析的情况,就有了窗口函数(MySQL是8.0版本开始才支持的窗口函数),也被称为OLAP函数(OnLine Analytical Processing)。

它有两个关键字partition by和order by:partition by是分区、分组,能够为我们要排序、或者求和、统计的对象划定一个区域(窗口),partition by可以没有,即不划定小的区域,针对所有的数据。order by是指定按照哪一列、何种顺序进行排序,是对销量还是什么指标进行排序,是升序还是降序。关于排名的窗口函数:ROW_NUMBER()、RANK()、DENSE_RANK(),首先需要记住它们三的区别,即针对相同数据的情况是否会“跳号”,然后就是它们的用法。

下篇会继续介绍窗口函数的其它知识和实际案例,希望这篇文章对你有帮助。如果你在学习或工作中遇到相关问题,欢迎随时交流探讨!

—END—

相关文章:

  • 为什么android要使用Binder机制
  • 顶级思维方式——认知篇九(经典语录)《约翰·克利斯朵夫》
  • LangChain4j从入门到实战(一)
  • DeepSeek今天喝什么随机奶茶推荐器
  • [C#] Task
  • 飞算 JavaAI:重构 Java 开发范式的工程化实践
  • Prim(普里姆)算法
  • 网络/信号/电位跟踪
  • 嘉讯科技:医院电子病历系统的关键性作用
  • 60天python训练计划----day56
  • 深入浅出Node.js后端开发
  • UE5 AnimMontage 的混合(Blend)模式
  • Qt for OpenHarmony 编译鸿蒙调用的动态库
  • WPF中MVVM和MVVMLight模式
  • 卷积运算的历史
  • Gateway路径匹配规则易错点
  • Recent Advances in Speech Language Models: A Survey
  • JVM调优详解(二)
  • AI大模型之机器学习理论及实践:监督学习-机器学习的核心基石
  • 北斗导航深度接入小程序打车:高精度定位如何解决定位漂移难题?
  • 免费培训学校网站源码/友情链接交换工具
  • 有名做网站公司/百度有专做优化的没
  • 北京海淀月嫂家政公司/优化设计电子版
  • 政府网站建设立规矩/网店运营策划方案
  • 一个网站做多少内链合适/seo怎么做最佳
  • 校园网站策划书/如何做企业网站