经常写SQL脚本的朋友,通常会有一种迷之自信,似乎各种问题都有自己的一套解决方案。时间长了,人的思维可能会逐渐固化。思维固化能提高工作效率,但从某些角度看是很可怕的,我们也同时会失去接受新知识的内在动力

从一个简单问题开始,数据库SQL应用最简单的是什么?很多朋友会脱口而出:当然是查询啦,select * from 表,多简单啊。如果我再问您,SQL最难搞的是什么?您可能会陷入沉思,一幕幕曾经的彻夜查资料痛苦尝试的经历一一浮现眼前。

有丰富经验的朋友,最可能的回答应该还是:查询最难搞!没错,SQL最简单的应用是查询、最难搞的应用也是查询。为什么会这样?!道理非常简单,因为查询语句虽然起点很低、但查询的需求非常多样化、查询的语法也非常复杂!

SQL开窗函数,主流数据库都支持的一朵奇葩

知识和技术总是要一点一点消化和积累的。今天,我们就谈谈查询中非常另类的一条语法:select子句的over函数。over函数在MySQL和SQL Server中被称为开窗函数、在PostgreSQL中被称为窗口函数、在Oracle中被称为分析函数、在DB2中被称为OLAP函数。

看来over函数虽然名字不同,但在主流数据库中都是支持的。这也不奇怪,这本来就是SQL标准中定义的函数。over函数在标准SQL中定义就叫开窗函数。不同数据库中虽然叫法不同,但语法格式和功能效果基本是一致的。

那开窗函数到底是什么呢?

复杂的定义我们就不说了,简单来讲,开窗函数类似于聚合函数(group by),主要实现数据的分组统计,为统计行打开一扇另类的统计窗口。over在某些情况下可以完全替代group by,但大多情况下,over比group by更灵活、更强大

更进一步来对比:group by是针对整个查询设置统一的分组字段,所有返回的分组统计必须以group by指定的分组条件为基准;而over则灵活多了,over 不需要基于分组字段进行统计,可以各自灵活指定分组依据。这意味着什么,相信您很容易就能想明白。

今天我们就以SQL Server为例,详细讲解一下如何具体应用开窗函数。

从最常见的count(*)引出开窗函数应用

了解一点数据库SQL的朋友应该知道,SQL中有一个count函数,这个函数是做什么用的?我不用说大家肯定都清楚,就是统计记录条数的呗!

没错,count函数确实是用来统计记录条数的,如果count函数的作用仅仅是这些的话,我就没必要提她了。简单的count函数,却引出了非常神奇的用途,怎么个神奇法呢?且听我缓缓道来。

先来点老套路,我们先看看我们都知道的count函数的语法格式:

select count(*、字段、表达式) from 表

这就是我们都知道的count的基本用法,确实非常简单,似乎没什么好说的。

其实,count除了统计记录条数之外,还有一个很神奇的功能,如果把count函数配合over开窗函数,就可以实现非常神奇的分组计数功能;我们熟知的sum函数再配合over函数,还可以实现分组汇总功能。这些统计功能在很多情况下,甚至比group by更简单、更好用。

演示数据准备

为了演示方便,我们先准备一套演示数据,创建一个表变量,存放不同区域、城市、年月的销售金额。脚本如下:

declare @sale table( FName nvarchar(50), FDistrict nvarchar(50), FYear smallint, FMonth smallint, FAmount decimal(28,10));insert into @salevalues('张三','北京',2019,4,20000),('张三','深圳',2019,4,40000),('李四','北京',2019,4,30000),('李四','深圳',2019,4,40000),('王二','北京',2019,4,70000),('王二','深圳',2019,4,60000),('马六','北京',2019,4,80000),('马六','深圳',2019,4,70000);

演示数据运行效果如下图所示:

下面我们就以演示数据为背景讲解下over函数的具体应用。

配合count按字段分组获取记录条数

这个用法与我们所熟知的count的含义类似,也是返回记录条数的,但配合over关键字却可以根据字段进行分组,返回不同分组的统计个数,语法格式如下:

count(*) over(partition by 字段列表)

比如我们想获得按照业务员名称返回记录条数,可以这样写:

select FName,FDistrict,count(*) over(partition by FName) as FCount from @sale;

运行效果如下图所示:

如上图所示,每一行返回的FCount字段的值,就是不同FName的个数统计,这里都显示2,是因为刚好每个业务员都有2条记录。

往常我们写SQL脚本做如此处理时,最常用的写法就是通过group by,但这里用count却更简单,您说不是嘛。

本节我们引出了over关键字,下面我们就引申一下,体验一回over关键字更神奇的用途:使用over关键字配合sum进行分组合计。

配合sum按字段进行分组合计

我们都知道,惯常来说分组统计要用group by,针对分组字段使用sum函数统计。其实还有一种另类的实现方式,sum函数和over函数配合使用,完全不用group by,却能实现比使用group by更加灵活的统计实现

我们先看看实现的语法格式:

sum(合计字段) over(partition by 分组字段列表)

下面我们就实战一下各种分组汇总方式,代码如下:

select  FName, FDistrict, sum(FAmount) over() as F整体, sum(FAmount) over(partition by FDistrict) as F按区域, sum(FAmount) over(partition by FName) as F按业务员, sum(FAmount) over(partition by FName,FDistrict) as F区域业务员from @sale;

运行效果如下:

您发现了没有,我们并没有使用group by子句,前两个字段FName和FDistrict自动成为分组字段,这种分组只是决定了分组的每一行,而真正的统计标准,则是按照over关键字指定的分组依据对sum指定的字段进行汇总。

这确实比Group By这种聚合函数要好用多了,我们可以随意指定想要的分组依据,宝宝们再也不用为了实现不同分组汇总数据写一堆子查询或公用表表达式气得跳脚了

配合排名函数让您的查询飞的更精彩

看过我上一篇文章(《善用SQL排名函数,让您的查询飞的更精彩》)的朋友,您肯定已经领教过了天窗函数的神奇应用,怎么个神奇法,具体您可以看看文中所述,这里我只做简单的讲述。

SQL有四大排名函数,分别为:ROW_NUMBER、RANK、DENSE_RANK、NTITLE。

ROW_NUMBER:主要实现最基本的序列化排名,返回的是行号,也可以用来分页查询。

其语法格式为:

row_number() over(order by field列表 asc|desc)

RANK:主要实现分组序列化排名,返回的组号。其语法格式为:

rank() over(order by field列表 asc|desc)

DENSE_RANK:与RANK类似,唯一的区别是,RANK的组号是基于行号的,相同值共用组号,碰到下一组不相同的,会跳过直接使用对应的行号做组号;DENSE_RANK则只考虑组号的连续性,不考虑行号。

其语法格式为:

dense_rank() over(order by field列表 asc|desc)

NTITLE:比较另类的功能,主要实现在排序的前提下,根据要求分多少组、再对查询结果分组。其逻辑简单说是将所有记录排序后,按照记录条数和组数要求尽量均分,返回的则是连续组号如果能够均分则均分,如果不能均分,则优先多分前面的组,后续组再按照均分原则依次类推

其语法格式为:

ntile(组数) over(order by field列表 asc|desc)

您明显能看到,多了一个“组数”参数,就是用来指定对查询结果分多少组用的。

over天窗函数配合排名函数的应用,我这里就不举例了,具体您可以参考《善用SQL排名函数,让您的查询飞的更精彩》。


今天讲的比较多,下面我们把知识点总结一下:

1、计数分组:count(*) over(partition by 分组字段列表)

2、汇总分组:sum(字段) over(partition by 分组字段列表)

3、ROW_NUMBER排名:row_number over(order by 排序字段列表 asc|desc)

4、RANK分组排名:rank over(order by 排序字段列表 asc|desc)

5、DENSE_RANK分组排名:dense_rank over(order by 排序字段列表 asc|desc)

6、NTITLE分组排名:ntitle(组数) over(order by 排序字段列表 asc|desc)


文中我多次提到“另类”二字,说实话开窗函数一点也不另类,另类的可能是我们的思维早已经被Group By固化了,没留意或没深入了解更神奇的over函数而已,您说呢?

怎么样?有没有觉得很神奇?!希望对您有所帮助!

mysql开窗函数_魔幻的SQL开窗函数,为您打开进阶高手的一扇天窗相关推荐

  1. sql字符串函数_另一堆SQL字符串函数

    sql字符串函数 This article is a supplement to the previously published article, An overview of SQL String ...

  2. mysql bitand函数_有趣的SQL(一)

    原标题:有趣的SQL(一) 大家都想提高自己的SQL能力,但是SQL能力也是需要慢慢提高的,为了让大家的SQL有所提高,特整理了下面的SQL. 需求:如下所示,有从1开始的2的幂的数组 - - 1, ...

  3. mysql sql总计函数_请问select SQL 语言中常用的合计函数有哪些?

    1.sql中sum和count的区别 ----sql聚合函数 (1)首先,sum是对一个字段求和,hive中字段的类型一般是string或者是int,如果是int当然没有问题,如果是string类型但 ...

  4. sql date 函数_什么是SQL DATE()函数?

    sql date 函数 Hey, folks! In this article, we will be focusing on SQL DATE() function in detail. So, l ...

  5. coalesce函数_什么是SQL Server COALESCE()函数?

    coalesce函数 Hey, folks! In this article, we will be focusing on SQL Server COALESCE() function. 嘿伙计! ...

  6. sql instr函数_如何实现SQL INSTR()函数?

    sql instr函数 Hey, folks! In this article, we will be understanding SQL INSTR() function in detail. 嘿伙 ...

  7. sql dateadd函数_什么是SQL Server DATEADD()函数?

    sql dateadd函数 Hey, folks! In this article, we will be focusing on SQL Server DATEADD() function in d ...

  8. hive substr函数_数据分析工具篇——HQL函数及逻辑

    本篇文章我们梳理一下hive常用的函数,对于hive而言,常用的函数并不是特别多,往往记住关键几个,就可以解决80%的问题,这也是大家喜欢hive的原因,那么,常用的函数有哪些呢? 时间函数 1)时间 ...

  9. decode函数_「实践」云函数 + API,你也可以做个天气信息系统

    为什么要把云函数 SCF 与 API 网关进行结合?本文告诉你答案! 通常,我们用云函数 SCF 写一个函数应用,这个应用可能多种多样.例如之前介绍过的 OJ 系统判题功能,通过 NLP 实现文本摘要 ...

最新文章

  1. 吴恩达老师深度学习视频课笔记:逻辑回归公式推导及C++实现
  2. java和c 的rsa加密算法_RSA算法签名技术Java与C++统一(加密解密结果一样)
  3. 【概率论与数理统计】假设检验
  4. linux小工具(2)终端记录器script命令
  5. java 字符长度 中文_java判断中文字符串长度的简单实例
  6. 用JS解决多行溢出文本的省略问题
  7. php mysql 快餐_用PHP+MYSQL做一个简单的点餐系统的后台,初学者. 请高手指点下如何实现后台添加菜名 餐馆 价格...
  8. 基于Linux的SOCKET编程之TCP半双工Client-Server聊天程序
  9. 一文理解接口和抽象类
  10. 如何把GIT项目push到公司review服务器
  11. linux mint xmind运行,linux安装Xmind的经验
  12. omv搭建php,家用NAS系统openmediavault插件开发
  13. 管鲍计算机教室管理系统,管鲍多媒体电子教室
  14. python爬京东联盟_Python+Selenium+Chrome抓取京东商品信息
  15. 使用Graphics2D给图片加水印(图片+图标)
  16. 又一年的五一劳动节!
  17. 某程序员在网吧敲代码,出类拔萃,网友:为何我被打的却是我
  18. 数据平台开发是做什么的?需要具备哪些能力
  19. 7、Instant-ngp
  20. boost库的安装和使用

热门文章

  1. MongoDB 安装与启动
  2. Ruby的Range类
  3. C#Winform编程的基础知识
  4. Manjaro oh-my-zsh安装配置
  5. Java多线程_JUC包下的阻塞队列
  6. IdentityServer4客户端JWT解密实现(基于.net4.0)
  7. mysql 性能优化 20 条建议
  8. android studio 1.2.1.1导入library project(以sharesdk为例)
  9. unix 网络编程总结
  10. SpringBoot中.properties文件中配置项显示到页面中文乱码解决