简介
SQL Server 2012之后对窗口函数进行了极大的加强,但对于很多开发人员来说,对窗口函数却不甚了解,导致了这样强大的功能被浪费,因此本篇文章主要谈一谈SQL Server中窗口函数的概念。
什么是窗口函数
窗口函数,也可以被称为OLAP函数或分析函数。理解窗口函数可以从理解聚合函数开始,我们知道聚合函数的概念,就是将某列多行中的值按照聚合规则合并为一行,比如说Sum、AVG等等,简单的概念如图1所示。
1
图1.聚合函数
因此,通常来说,聚合后的行数都要小于聚合前的行数。而对于窗口函数来说,输入结果等于输出结果,举一个简单的例子,如果你计算产品类型A和产品类型B,A产品分5小类,B产品分2小类,应用了窗口函数的结果后可以还是7行,对窗口函数应用了Count后,附加在每一行上,比如说“A产品,A小类1,5“,而B小类则变为”B产品,B小类1,2”最后一列就是应用了窗口函数的结果。
现在我们对窗口函数有了初步的概览,文章后我会提供一些具体的例子来让对窗口函数的概念更加深刻,窗口函数除了上面提到的输入行等于输出行之外,还有如下特性和好处:
类似Group By的聚合
非顺序的访问数据
可以对于窗口函数使用分析函数、聚合函数和排名函数
简化了SQL代码(消除Join)
消除中间表
窗口函数是整个SQL语句最后被执行的部分,这意味着窗口函数是在SQL查询的结果集上进行的,因此不会受到Group By, Having,Where子句的影响。
窗口函数的典型范例是我们在SQL Server 2005之后用到的排序函数,比如代码清单1所示。
Row_Number() OVER (partition by xx ORDER BY xxx desc) RowNumber
代码清单1.可用于分页的排序函数
因此,我们可以把窗口函数的语法抽象出来,如代码清单2所示。
函数() Over (PARTITION By 列1,列2,Order By 列3,窗口子句) AS 列别名
代码清单2.窗口函数的语法
一个简单的例子
下面我们来看一个简单的例子,假如说我们希望将AdventureWorks示例数据库中的Employee表按照性别进行聚合,比如说我希望得到的结果是:“登录名,性别,该性别所有员工的总数”,如果我们使用传统的写法,那一定会涉及到子查询,如代码清单3所示。
SELECT [LoginID],gender,
(SELECT COUNT(*) FROM [AdventureWorks2012].[HumanResources].[Employee] a WHERE a.Gender=b.Gender) AS GenderTotal
FROM [AdventureWorks2012].[HumanResources].[Employee] b
代码清单3.传统的写法
如果我们使用了窗口函数,代码瞬间就变得简洁,不再需要子查询或Join,如图2所示。
2
图2.使用窗口函数
除此之外,窗口函数相比传统写法而言,还会有更好的性能,我们可以通过比较执行计划得出如图3所示。
3
图3.通过比较执行计划,看出窗口函数拥有更好的性能
假如我们考虑更复杂的例子,在Over子句加上了Order By,来完成一个平均数累加,如果不使用窗口函数,那一定是游标,循环等麻烦的方式,如果使用了窗口函数,则一切就变得非常轻松,如图4所示。
4
图4.窗口函数
Partition By
代码清单2展示了窗口函数的语法,其中Over子句之后第一个提到的就是Partition By。Partition By子句也可以称为查询分区子句,非常类似于Group By,都是将数据按照边界值分组,而Over之前的函数在每一个分组之内进行,如果超出了分组,则函数会重新计算,比如图2中的例子,我们将数据分为男性和女性两部分,前面的Count()函数针对这两组分别计算值(男性206,女性84)。
针对Partition By可以应用的函数不仅仅是我们所熟知的聚合函数,以及一些其他的函数,比如说Row_Number()。
Order By
Order By子句是另一类子句,会让输入的数据强制排序(文章前面提到过,窗口函数是SQL语句最后执行的函数,因此可以把SQL结果集想象成输入数据)。Order By子句对于诸如Row_Number(),Lead(),LAG()等函数是必须的,因为如果数据无序,这些函数的结果就没有任何意义。因此如果有了Order By子句,则Count(),Min()等计算出来的结果就没有任何意义。
下面我们看一个很有代表性的ROW_NUMBER()函数,该函数通常被用于分页,该函数从1开始不断递增,可以和Partition By一起使用,当穿越分区边界时,Row_Number重置为1,一个简单的例子如图5所示,我们根据请假小时数对员工进行排序。
5
图5.Row_Number函数示例
另一个比较有趣的分析函数是LEAD()和LAG(),这两个分析函数经过Order By子句排序后,可以在当前行访问上N行(LAG)或下N行(LEAD)的数据,下面是一个例子,如图6所示。
6
图6.访问上一行的LAG函数
另一个分析函数是RANK函数,与Row_Number不同的是,Rank函数中如果出现了相同的值,不会像Row_Number那样叠加计数,而是同样的值计数一样,比如说 1 1 3 4 5 5 7,而不是Row_Number的1 2 3 4 5 6 7。这里就不细说了。另外如果希望并列排名的不影响下一个排名,则考虑使用Dense_Rank函数。有关其他的诸如First_value和Last_Value之类的函数可以参看:http://technet.microsoft.com/zh-cn/library/hh213234.aspx。
窗口子句
前面窗口的函数的作用范围是整个表,或是整个Partition by后面的分区。但是使用了窗口子句我们可以控制输入到窗口函数的数据集(前面说过,窗口函数是整个语句中最后执行的)的范围。下面我们从一个例子开始看,假如我希望找出公司每一个层级休病假最长的人,我们可以执行图7中的语句。
7
图7.找出每个层级休假最多的人
但是如果我们希望把输入数据集的粒度由Partition变为更细的话,我们可以使用窗口子句,让窗口函数仅仅根据当前行的前N行和后N行计算结果,那我们可以使用窗口子句,如图8所示,图8中,我们排序后,仅仅根据当前行的前一行和后一行以及当前行来计算这3个人当中请病假最长时间的人。
8
图8.在三行之内找到休假时间最长的人
我们也可以使用Range来指定Partition内的范围,比如说我们希望从当前行和之前行中找到第一行,则使用如图9所示的用法。
9
图9.
小结
本文从窗口函数组成的三部分简单介绍了窗口函数的概念,并给出了一些例子。更多可以在窗口上使用的函数,可以参照MSDN(http://technet.microsoft.com/zh-cn/library/ms189461.aspx)。在使用这些函数的时候,还要注意版本要求,很多函数是只有在SQL Server 2012中才被支持的。
分类: 窗口函数
本文转自CareySon博客园博客,原文链接:http://www.cnblogs.com/CareySon/p/3411176.html,如需转载请自行联系原作者

SQL Server中的窗口函数相关推荐

  1. 在SQL Server中分页结果的最佳方法是什么

    如果您还希望获得结果总数(在进行分页之前),那么在SQL Server 2000.2005.2008.2012中对结果进行分页的最佳方法是(性能明智的)? #1楼 最终, Microsoft SQL ...

  2. 在SQL Server中以运行总计运行

    背景 (Background) Running totals have long been the core of most financial systems, be statements or e ...

  3. percent sql_使用SQL Server中的PERCENT_RANK函数计算SQL百分位数

    percent sql This article explores the SQL Server PERCENT_RANK analytical function to calculate SQL P ...

  4. SQL Server中Identity标识列

    SQL Server中,经常会用到Identity标识列,这种自增长的字段操作起来的确是比较方便.但它有时还会带来一些麻烦. SQL Server中,经常会用到Identity标识列,这种自增长的字段 ...

  5. predicate 列存储索引扫描_在SQL SERVER中导致索引查找变成索引扫描的问题分析

    SQL Server 中什么情况会导致其执行计划从索引查找(Index Seek)变成索引扫描(Index Scan)呢? 下面从几个方面结合上下文具体场景做了下测试.总结.归纳. 1:隐式转换会导致 ...

  6. mysql2008 limit,在SQL Server中实现 Limit m, n 的功能

    在SQL Server中实现 Limit m, n 的功能 (2012-03-14 18:17:43) 标签: 杂谈 在MySQL中,可以用 Limit 来查询第 m 列到第 n列的记录,例如: se ...

  7. SQL Server中SELECT会真的阻塞SELECT吗?

    在SQL Server中,我们知道一个SELECT语句执行过程中只会申请一些意向共享锁(IS) 与共享锁(S), 例如我使用SQL Profile跟踪会话86执行SELECT * FROM dbo.T ...

  8. 将Session值储存于SQL Server中

    一般情况下,我们喜欢使用Session储存我们的变量.Asp.Net提供了下面一些方法储存Session的值: InProc State Server SQL Server "InProc& ...

  9. 在SQL Server中保存和输出任意类型的文件

    我们可以把任意类型的文件保存到SQL Server中,在进行例子之前,先建立测试用表格,TestFile.sql: if exists (select * from dbo.sysobjects wh ...

最新文章

  1. 在论坛如何写好原创技术贴
  2. 基于supersocket、C#对JT808协议进行解析构建gps监控平台服务端
  3. ML之FE:数据处理—特征工程之高维组合特征的处理案例(矩阵分解)——基于LoR算法的广告点击预估问题
  4. 小明分享|分享8ms平台sigmastar SSD201/SSD202 开源框架的github
  5. 服务器端使用jsp还是asp_快速了解 ASP.NET Core Blazor
  6. python 数字证书模拟登录_用于生成WebService使用的数字证书及签署证书.python脚本...
  7. 堡垒之夜一年内增1亿玩家、YouTube为支持AV1的8K电视提供8K内容、Elon Musk要过极简生活等...
  8. 语言速算24点的小窍门_4秒钟1道题!12岁少年三夺24点大赛冠军
  9. python中的累乘积_Python中的连续元素最大乘积
  10. SpringBoot:javalist和set区别
  11. 最擅长玩《毁灭战士》的AI开源了 | 来自CMU的论文代码
  12. 图像处理------泛洪填充算法(Flood Fill Algorithm) 油漆桶功能
  13. hdu 3461 Code Lock(并查集)2010 ACM-ICPC Multi-University Training Contest(3)
  14. Cordova - 彻底搞定安卓中的微信支付插件!
  15. 【Eclipse使用教程】Java导包快捷键
  16. 有没免费云桌面,免费桌面虚拟化软件? 确实有的
  17. 0元参会丨第十届数据技术嘉年华精彩抢先速览
  18. iOS Code Signing 学习笔记转写
  19. 尚硅谷大数据superset安装包冲突
  20. 计算机中颜色质量,win10系统更改颜色质量的操作技巧

热门文章

  1. [Java] 蓝桥杯ALGO-103 算法训练 完数
  2. 如何在Dev-Cpp中使用C++11中的函数:stoi、to_string、unordered_map、unordered_set、auto
  3. CCCC-GPLT L1-038. 新世界 团体程序设计天梯赛
  4. 【mac】Snagit截图时候鼠标变大太大的解决方法
  5. 记录拷贝:centos安装jdk
  6. C++回声服务器_6-多进程pipe版本服务器
  7. 作业四:个人项目-小学四则运算之JAVA版
  8. DevExpress v18.1新版亮点——WPF篇(二)
  9. mysql 异常笔记
  10. BIND配置文件详解(二)