您当前的位置:首页 > 电脑百科 > 数据库 > 百科

善用SQL排名函数,让您的查询飞的更精彩

时间:2019-04-08 13:29:43  来源:  作者:

经常写SQL脚本的朋友,对查询的多样化要求可能会经常头疼。数据库SQL的语法是固定的、但应用要求却是千差万别的。依靠我们所掌握的知识,大部分的查询需求我们还是有办法的解决的,但总有那么一些要求,把我们搞的非常被动。

善用SQL排名函数,让您的查询飞的更精彩

 

今天我们就谈一个会让我们头疼的问题:如何对查询的结果进行排名。没错,是排名,不是排序,跟Order By有点关系,但可以认为是另一个问题。排名函数不但可以实现排序,还能够生成排序的排名序列

演示数据准备

今天我们就以SQL Server为例,结合四大排名函数,详细讲解一下如何使用四大排名函数实现查询结果的排名。MySQL也有类似的排名函数,使用方法与SQL Server大同小异

为了演示需要,我们需要先创建一个表变量作为销售表,记录不同区域、城市、年月的销售金额,然后再对表中的数据进行排名处理。演示数据创建脚本如下:

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

运行结果请参考下图:

善用SQL排名函数,让您的查询飞的更精彩

 

有了演示数据,我们就把四个排名函数的应用和区别挨个理一理。

ROW_NUMBER,简单方便又强大

row_number是最常用、最简单的排名函数,其语法格式如下:

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

语法格式看上去有点怪怪的,前半截row_number()是排名函数,紧接其后的over子句则是指定排序的规则。其它三个排名函数也有over子句,用途和语法也是一样的。整个函数作为一个整体,其返回值就是排名序列号,序列号从1开始依次累加。

比如我们要按照销售金额进行排名,语法格式如下:

select ROW_NUMBER() over(order by FAmount desc) as FRank,* from @sale;

运行效果参考下图:

善用SQL排名函数,让您的查询飞的更精彩

 

通过上图的查询结果可以看出,FRank字段就是返回的排名字段。根据over子句,可以定义任何自己需要的排名规则。

如果您认为row_number函数只是能实现如此排名,那您就想的太简单了。row_number函数还有一个很重要的扩展用途,可以实现查询分页,我们举一个例子来说明如何使用row_number实现查询分页。

为了使演示效果更明显,我们使用公用表表达式返回排名序列值和数据,根据要求的每页行数和第几页,通过where子句限定排名序列的起点和终点。

declare @pagesize int =4;--每页记录数
declare @pagenum int =1;--第几页
with cte as
(
 select row_number() over(order by FAmount desc) as FRank,*
 from @sale
)
select * from cte
where FRank between 
 @pagesize*(@pagenum-1)+1 
 and 
 @pagenum*@pagesize;

运行效果如下图所示:

善用SQL排名函数,让您的查询飞的更精彩

 

这种写法基本是通用的,您可以比葫芦画瓢稍加改造,就可以用在您的分页脚本中。

如果在查询中使用order by子句,要注意order by子句最好与排名中over子句的order by一致,如果不一致,可能导致返回排名序列是不连续的,但这并不影响数据页的正确性。

还有一种可以实现分页写法,使用offset进行分页,这里我就不再赘述了。如果您想要更进一步了解分页语法,可以参考我之前写过的文章《如何在SQLServer查询中实现高效分页》。

RANK,相同值共用排名值,跳着排

RANK函数与ROW_NUMBER函数的语法和效果类似,最大的区别在于,如果碰到相同的字段值,会使用相同的排名序列值,后续的序列值则会跳过共用序列值。

其语法格式如下:

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

下面我们就实战一下:

select RANK() over(order by FAmount desc) as FRank,* from @sale;

运行效果如下图所示:

善用SQL排名函数,让您的查询飞的更精彩

 

我们从上图可以很明显看出来,第2、3条记录因值相同,使用了相同的序列值“2”,到了第四条,排名序列值直接使用了“4”而跳过了“3”。

DENSE_RANK,相同值共用排名值,接着排

DENSE_RANK函数与RANK函数的语法和效果类似,区别就像函数名称中的DENSE(紧密的)含义一样,如果碰到相同的字段值,虽然都会使用相同的排名序列值,但序列值是连续的。

其语法格式如下:

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

下面我们就实战一下:

select DENSE_RANK() over(order by FAmount desc) as FRank,* from @sale;

运行效果如下图所示:

善用SQL排名函数,让您的查询飞的更精彩

 

可以看出RANK和DENSE_RANK确实有共同点,但也有区别。RANK排名值如果碰到相同字段值,则会使用相同的排名值,后续会跳过断开使用新的排名值;DENSE_RANK碰到相同字段值同样使用相同的排名值,但是接着排下来,不会断开

NTILE,根据约定分组

NTILE函数的语法和用途上面三个明显不同,其功能主要用来实现对记录进行分组。根据NTILE约定分组的组数,将查询结果按照over子句的排序标准进行分组,分组组号按照序列排列,同一个组使用同一个组号。

其语法格式如下:

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

如果指定的组数刚好实现均分,则每一组的记录数是相同的,比如我们将8条记录分成四组,则会有四个组,组号分别是1、2、3、4,每一组都会有两个记录,举例如下:

select NTILE(4) over(order by FAmount desc) as FRank,* from @sale;

运行效果如下:

善用SQL排名函数,让您的查询飞的更精彩

 

如果分成五组,明显无法均分,那如何分呢?

当然是有一种逻辑存在的。这种逻辑可以这样理解,从第一组开始,使用总记录数除以组数,获取等于或最大于相除结果的最小整数,作为第一组的记录条数;剩余的记录条数按照相同算法依次类推。通俗来讲,NTITLE在优先配足靠前的分组的记录数的前提下,尽量进行均分。

下面我们我实战将以上记录分成五组的执行情况:

select NTILE(5) over(order by FAmount desc) as FRank,* from @sale;

运行效果如下:

善用SQL排名函数,让您的查询飞的更精彩

 

从上图可以看出,记录条数是8条,分成5组,我们用8除以5,最接近且大于等于的整数是2,第一组占用了两条记录,这时候还剩余6条记录分4组;依次类推,6除以4,最接近且大于等于的整数是2,第二组还是2条记录;此时剩余4条记录要分3组,4除以3,最接近且大于等于的整数还是2;再往下,剩余两条分两组,这时候就刚好均分了。

需要明确的是,NTILE也可用来分页,但因分组逻辑的原因,效果就不如ROW_NUMBER理想了。


通过上述分析,我们对排名函数就有了充分的认识,您大可根据需要使用。希望对您有所帮助!



Tags:SQL   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
1增1.1【插入单行】insert [into] <表名> (列名) values (列值)例:insert into Strdents (姓名,性别,出生日期) values (&#39;开心朋朋&#39;,&#39;男&#39;,&#39;1980/6/15&#3...【详细内容】
2021-12-27  Tags: SQL  点击:(2)  评论:(0)  加入收藏
作者:雷文霆 爱可生华东交付服务部 DBA 成员,主要负责Mysql故障处理及相关技术支持。爱好看书,电影。座右铭,每一个不曾起舞的日子,都是对生命的辜负。 本文来源:原创投稿 *爱可生...【详细内容】
2021-12-24  Tags: SQL  点击:(7)  评论:(0)  加入收藏
前言JDBC访问Postgresql的jsonb类型字段当然可以使用Postgresql jdbc驱动中提供的PGobject,但是这样在需要兼容多种数据库的系统开发中显得不那么通用,需要特殊处理。本文介绍...【详细内容】
2021-12-23  Tags: SQL  点击:(13)  评论:(0)  加入收藏
最近发现还有不少做开发的小伙伴,在写存储过程的时候,在参考已有的不同的写法时,往往很迷茫, 不知道各种写法孰优孰劣,该选用哪种写法,以及各种写法的优缺点,本文以一个简单的查询...【详细内容】
2021-12-23  Tags: SQL  点击:(9)  评论:(0)  加入收藏
场景描述:由于生产环境的表比较复杂,字段很多。这里我们做下简化,只为说明今天要聊的问题。有两张表 tab1,tab2: tab1 数据如下: tab2 数据如下: 然后给你看下,我用来统计 name=&#3...【详细内容】
2021-12-20  Tags: SQL  点击:(7)  评论:(0)  加入收藏
概述我们知道SQL Server是微软公司推出的重要的数据库产品,通常情况下只支持部署在windows平台上。不过令人感到兴奋的是,从SQL Server 2017开始支持 linux系统。此 SQL Serve...【详细内容】
2021-12-17  Tags: SQL  点击:(13)  评论:(0)  加入收藏
读取SQLite数据库,就是读取一个路径\\192.168.100.**\position\db.sqlite下的文件<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/...【详细内容】
2021-12-16  Tags: SQL  点击:(21)  评论:(0)  加入收藏
前言知识无底,学海无涯,知识点虽然简单,但是比较多,所以将MySQL的基础写出来,方便自己以后查找,还有就是分享给大家。一、SQL简述1.SQL的概述Structure Query Language(结构化查...【详细内容】
2021-12-16  Tags: SQL  点击:(13)  评论:(0)  加入收藏
一、为什么要搭建主从架构呢1.数据安全,可以进行数据的备份。2.读写分离,大部分的业务系统来说都是读数据多,写数据少,当访问压力过大时,可以把读请求给到从服务器。从而缓解数据...【详细内容】
2021-12-15  Tags: SQL  点击:(12)  评论:(0)  加入收藏
前言作为一名测试工程师,工作中在对测试结果进行数据比对的时候,或多或少要和数据库打交道的,要和数据库打交道,那么一些常用的 SQL 查询语法必须要掌握。最近有部分做测试小伙...【详细内容】
2021-12-14  Tags: SQL  点击:(15)  评论:(0)  加入收藏
▌简易百科推荐
1增1.1【插入单行】insert [into] <表名> (列名) values (列值)例:insert into Strdents (姓名,性别,出生日期) values (&#39;开心朋朋&#39;,&#39;男&#39;,&#39;1980/6/15&#3...【详细内容】
2021-12-27  快乐火车9d3    Tags:SQL   点击:(2)  评论:(0)  加入收藏
最近发现还有不少做开发的小伙伴,在写存储过程的时候,在参考已有的不同的写法时,往往很迷茫, 不知道各种写法孰优孰劣,该选用哪种写法,以及各种写法的优缺点,本文以一个简单的查询...【详细内容】
2021-12-23  linux上的码农    Tags:sql   点击:(9)  评论:(0)  加入收藏
《开源精选》是我们分享Github、Gitee等开源社区中优质项目的栏目,包括技术、学习、实用与各种有趣的内容。本期推荐的HasorDB 是一个全功能数据库访问工具,提供对象映射、丰...【详细内容】
2021-12-22  GitHub精选    Tags:HasorDB   点击:(5)  评论:(0)  加入收藏
作者丨Rafal Grzegorczyk译者丨陈骏策划丨孙淑娟【51CTO.com原创稿件】您是否还在手动对数据库执行各种脚本?您是否还在浪费时间去验证数据库脚本的正确性?您是否还需要将...【详细内容】
2021-12-22    51CTO  Tags:Liquibase   点击:(4)  评论:(0)  加入收藏
场景描述:由于生产环境的表比较复杂,字段很多。这里我们做下简化,只为说明今天要聊的问题。有两张表 tab1,tab2: tab1 数据如下: tab2 数据如下: 然后给你看下,我用来统计 name=&#3...【详细内容】
2021-12-20  Bald    Tags:SQL   点击:(7)  评论:(0)  加入收藏
前言知识无底,学海无涯,知识点虽然简单,但是比较多,所以将MySQL的基础写出来,方便自己以后查找,还有就是分享给大家。一、SQL简述1.SQL的概述Structure Query Language(结构化查...【详细内容】
2021-12-16  谣言止于独立思考    Tags:SQL基础   点击:(13)  评论:(0)  加入收藏
前言作为一名测试工程师,工作中在对测试结果进行数据比对的时候,或多或少要和数据库打交道的,要和数据库打交道,那么一些常用的 SQL 查询语法必须要掌握。最近有部分做测试小伙...【详细内容】
2021-12-14  柠檬班软件测试    Tags:SQL   点击:(15)  评论:(0)  加入收藏
话说C是面向内存的编程语言。数据要能存得进去,取得出来,且要考虑效率。不管是顺序存储还是链式存储,其寻址方式总是很重要。顺序存储是连续存储。同质结构的数组通过其索引表...【详细内容】
2021-12-08  小智雅汇    Tags:数据存储   点击:(18)  评论:(0)  加入收藏
概述DBConvert Studio 是一款强大的跨数据库迁移和同步软件,可在不同数据库格式之间转换数据库结构和数据。它将成熟、稳定、久经考验的 DBConvert 和 DBSync 核心与改进的现...【详细内容】
2021-11-17  雪竹聊运维    Tags:数据库   点击:(26)  评论:(0)  加入收藏
一、前言 大家好,我是小诚,《从0到1-全面深刻理解MySQL系列》已经来到第四章,这一章节的主要从一条SQL执行的开始,由浅入深的解析SQL语句由客户端到服务器的完整执行流程,最...【详细内容】
2021-11-09  woaker    Tags:SQL   点击:(35)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条