经常写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 @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);

运行结果请参考下图:

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

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;

运行效果参考下图:

通过上图的查询结果可以看出,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 ctewhere FRank between  @pagesize*(@pagenum-1)+1  and  @pagenum*@pagesize;

运行效果如下图所示:

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

如果在查询中使用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;

运行效果如下图所示:

我们从上图可以很明显看出来,第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;

运行效果如下图所示:

可以看出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;

运行效果如下:

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

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

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

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

运行效果如下:

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

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


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

sql 除以_不可思议的SQL排名函数,被您无视了么?相关推荐

  1. sql 除以_避免SQL除以零错误的方法

    sql 除以 This article explores the SQL divide by zero error and various methods for eliminating this. ...

  2. sql 除以_使用SQL分析游戏运营情况

    数据来源:http://www.dcjingsai.com/common/cmpt/%E6%B8%B8%E6%88%8F%E7%8E%A9%E5%AE%B6%E4%BB%98%E8%B4%B9%E9% ...

  3. mysql高效sql语句_高效SQL优化 非常好用的SQL语句优化34条

    高效SQL优化 非常好用的SQL语句优化34条 相关软件相关文章发表评论 来源:2011/2/13 9:38:43字体大小: 作者:佚名点击:576次评论:0次标签: 类型:电子教程大小:8.5M语言 ...

  4. 存储过程中定义sql语句_学习SQL:用户定义的存储过程

    存储过程中定义sql语句 Stored procedures (SPs) are one more powerful database object we have at our disposal. ...

  5. sql 缓冲池_监视SQL Server中的内存文员和缓冲池分配

    sql 缓冲池 The following article applies to SQL Server versions 2008 + 以下文章适用于SQL Server 2008 +版本 Adequ ...

  6. 免费的sql工具_免费SQL工具

    免费的sql工具 Adminer ApexSQL CI/CD toolkit ApexSQL Compare ApexSQL Complete ApexSQL Decrypt ApexSQL Plan ...

  7. 含有参数的sql拼接_关于SQL语句参数中为多个带.字符串。

    关于 SQL 语句参数中为多个带 ',' 的字符串 原本是这样 , 参数有 date,@didian insert into hp( 个人编号 , 身份证号 , 姓名 , 性别 , 民族 , 出生日期 ...

  8. sql 临时表_原创 | SQL优化之合理使用临时表

    看海景大图的推文吗?将我们设为星标★即可~ SQL专栏 SQL基础知识汇总 SQL高级知识汇总 今天我们来讲讲临时表的优化技巧 临时表,顾名思义就只是临时使用的一张表,一种是本地临时表,只能在当前查询 ...

  9. mysql超长sql查询_超长SQL怎么查询?MySQL列长度限制有哪些 | 学步园

    MySQL字符串的限制长度看似重要性不要,其实和整个MySQL数据库的安全性是息息相关的,很值得我们去深入研究分析.SQL注入攻击一直都在被广泛的讨论,然而人们却忽略了今天我将要介绍的这两个安全隐患, ...

最新文章

  1. OpenCV(项目)车牌识别2 -- 车牌字符分割(直方图)
  2. mui后端开发php,PHP解决mui中ajax的跨域问题
  3. 关于文件权限管理了解和使用
  4. 日记:2019-07-28
  5. php smart模板,vaphp整合smart模板有关问题
  6. tomcat基本知识点与实例
  7. Ember.js 入门指南——路由切换的终止和回跳
  8. android Fragments详解六:处理fragement的生命周期
  9. VS 2017番茄插件安装破解教程:visual assist
  10. 微软windows10易升_微软官网下载与安装windows10系统的操作步骤
  11. MobaXterm 复制粘贴快捷键
  12. matlab 绘制三维实体,matlab 三维绘制
  13. 360公司2019校招笔试编程题合集答案——python版本
  14. 强化Play To Earn生态,链游新势力海姆达尔Heimdallr蓄势待发
  15. 基于FPGA实现的数字位同步锁相环设计
  16. hyper-v 网桥_使用网桥简化网络-使FIO ActionTec MI424-WR成为网桥
  17. 2020美容师(初级)操作证考试及美容师(初级)作业模拟考试
  18. 电气工程师软件笔试题
  19. 知识欠缺到沙漠化了吧
  20. SiC碳化硅二极管抗浪涌电流能力缺点及应对方式

热门文章

  1. JMX的Hello World
  2. android程序大牛,冲向大牛之安卓:学习界面怎么在程序中画出来
  3. oracle管理认证方式,关于Oracle数据库管理员认证方法简述
  4. java 异常管理员_java web在进行管理员操作的时候,抛出了下面的异常,怎么解决啊...
  5. PAT_B_1065_Java(17分)_C++(25分)
  6. java 创建定时器_SpringBoot创建定时任务
  7. mysql版本 hibernate_Mysql 不同版本 说明
  8. 普罗米修斯监控系统_基于Prometheus和Grafana的监控平台 - 环境搭建
  9. Windows Terminal 完全配置教程(主题以及启动设置)
  10. Leetcode 2 两数相加 Python