SQL点滴20—T-SQL中的排名函数

原文:SQL点滴20—T-SQL中的排名函数

提到排名函数我们首先可能想到的是order by,这个是排序,不是排名,排名需要在前面加个名次序号的,order by是没有这个功能的。还可能会想到identity(1,1),它也给了一个序号,但是不能保证给出的序号是连续升序的。除非能够保证所有的Insert语句都能够正确成功地完成,并且没有删除操作,实际的使用中大多数的表都不能保证这样。

好在SQL Server中提供了一些排名函数来辅助实现这些功能。排名函数按照需要的顺序对数据进行排名,并提供一个值对数据。下面来了解一下这些排序函数功能。

  

ROW_NUMBER

 

ROW_NUMBER函数允许以上升,连续的顺序给每一行数据一个序号,注意ROW_NUMBER()后面一定要跟着over子句。来看语句:

1use AdventureWorks2select3ROW_NUMBER() over(order by LastName) as RowNum,4FirstName+‘ ‘+ LastName as FullName5from HumanResources.vEmployee6where JobTitle=‘Production Technician - WC60‘

这个语句对符合条件(JobTitle=‘Production Technician - WC60‘)的LastName按照升序排列,并加上排序的序号,这个序号是连续上升的。结果如下图1是部分结果。

图1

我们可以看到第一个人的LastName是Abercrombie,第二个人的LastName是Adams,以次类推。

  

PARTITION

 

如果我们想再细分一下,在一个小的分组范围内排序该怎么办呢?就是说让LastName以‘A’开头的作为第一组,在这个组内进行排序。以‘B’开头的作为第二组,在这个组内排序。以‘C’开头的作为第三组,在这个组内进行排序,如此等等。这里有一个很简单的实际例子,假如上面这些人都来参加同一场马拉松比赛,其中有男子组,女子组,男子残疾组,女子残疾组,60岁以上组等等。不管参赛者以第几位触线,名次都以他们的小组为基准。

可以通过PARTITION BY选项来重新排序,给数据分区或者数据区域唯一的递增序号。来看下面的语句:

[注] partition n. 划分,分开;[数] 分割;隔墙;隔离物;vt. [数] 分割;分隔;区分

1select2ROW_NUMBER() over(PARTITION by substring(LastName,1,1) order by LastName) as RowNum,3FirstName+‘ ‘+ LastName as FullName4from HumanResources.vEmployee5where JobTitle=‘Production Technician - WC60‘

这里模拟上面的情况,首先以Last Name的第一个字母作为分组,然后以第二个字母以后的字母来分组排序。来看看结果,如图2

?

?图2

假设LastName以‘A’开头的是男子组,这个组有共有三个人,Kim Abercrombie是冠军,Jay Adams是亚军,Nancy Anderson是季军。假设LastName以‘B’开头的是女子组,这个组只有一个人Bryan Baker,无论如何她都是冠军。等等如此类推。这样一眼就能看出他们的小组名次了。

这里你可能会觉得使用order by一样可以得到这样类似的结果。如下代码:

1 select 2 FirstName+‘ ‘+ LastName as FullName3 from HumanResources.vEmployee4 where JobTitle=‘Production Technician - WC60‘5 order by substring(LastName,1,1) ,LastName

这个把order by放在最后,排序放在最后,首先按照LastName的首字母排序,再按照剩整个LastName排序,结果如下图3

?

?图3

?结果和上面大致相同,可是少了前面的名次序号。于是我又对她进行了修改,代码如下:

1select 2ROW_NUMBER() over(order by substring(LastName,1,1),LastName) as RowNum,3FirstName+‘ ‘+ LastName as FullName4from HumanResources.vEmployee5where JobTitle=‘Production Technician - WC60‘

这个和上面的类似,在排名函数中使用order by,并且是按照多个字段排序。来看看结果如图4

?

图4

排序没有错误,是我们想要的分组排序,但是前面的名次没有分组区分,和图1没有什么差别。可见图3和图4的做法完全是多余,纯属臆造,其实只要order by LastName都能得到正确的排序,只有partition by才是正解。通过上面的例子也可以对排序,排名这二者之间的区别有一个认识,他们虽然有相似之处,但是排名始终会产生一个名次序号,排序只要得到正确的顺序就好。

    

RANK

 

还是拿马拉松比赛来说事,如果有同时撞线的情况发生应该怎么计名次呢?例如A第一个撞线,B和C同时第二个撞线,D第三个撞线,如果我们想把D的名次计为第4名应该怎么处理呢?就是说不计顺序名次,只计人数。这时就可以使用RANK函数了。

[注] rank n. 等级;队列;排;军衔vt. 排列;把…分等vi. 列队;列为

在order by子句中定义的列上,如果返回一行数据与另一行具有相同的值,rank函数将给这些行赋予相同的排名数值。在排名的过程中,保持一个内部计数值,当值有所改变时,排名序号将有一个跳跃。

来看下面的语句:

1select 2ROW_NUMBER() over(order by Department) as RowNum,3RANK() over(order by Department) as Ranking,4FirstName+‘ ‘+ LastName as FullName,5Department6from HumanResources.vEmployeeDepartment7order by RowNum

rank()函数右面也要跟上一个over子句。为了看到效果我们以Department作为排序字段,可以看到RowNum作为升序连续排名,Ranking作为计同排名,当Department的值相同时,Ranking中的值保持不变,当Ranking中的值发生变化时,Ranking列中的值将跳跃到正确的排名数值。来看结果:

?

?图5

?从这个结果中我们可以说这次马拉松赛跑的排名是:Tengiz Kharatishvili,Zainal Arifin,Sean Chai,Karen Berge,Chris Norred并列第1,Michael Sullivan,Sharon Salavaria,Roberto Tamburello,Gail Erickson,Jossef Goldberg并列第6,如此等等。

?

DENSE_RANK

在上面的例子中,A第一个撞线,B和C同时第二个撞线,D第三个撞线,如果我们想把B和C的名次计位第2名,D的名次计为第3名应该怎么处理呢?就是说考虑并列名次。这里使用DENSE_RANK函数,来看下面的代码。

1select2ROW_NUMBER() over(order by Department) as RowNum,3DENSE_RANK() over(order by Department) as Ranking,4FirstName+‘ ‘+ LastName as FullName,5Department6from HumanResources.vEmployeeDepartment7order by RowNum

结果如下:

?

?图6

按照这个结果,我们可以说这次马拉松赛跑的排名是:Tengiz Kharatishvili,Zainal Arifin,Sean Chai,Karen Berge,Chris Norred并列第1,Michael Sullivan,Sharon Salavaria,Roberto Tamburello,Gail Erickson,Jossef Goldberg,Terri Duffy并列第2,等等如此。

NTILE

在开始这个之前,先来一段小插曲。梭罗是铅笔的发明者,不过他没有申请专利。据说他天赋异禀,在父亲的铅笔厂里面打包铅笔的时候,从一堆铅笔里面抓取一把,每次都能精确地抓到一打12支。他在森林中目测两颗树之间的距离,和护林员用卷尺测量的结果相差无几。现在如果我们想从一张表中抓取多比数据,每一笔都是相同的数目,并且标明第几组该怎么办呢?NTILE函数提供了这个功能,他能。来看代码:

1 select 2 NTILE(30) over(order by Department) as NTiles,3 FirstName+‘ ‘+ LastName as FullName,4 Department5 from HumanResources.vEmployeeDepartment

现在我们要抓取30个组的数据,并保证尽可能的保证每组数目相同。结果如下,

?

?图7

?这个视图中共290条数据,290/30=9.7约等于10,所以每组10条数据,如图每一条数据都有一个组号。这个结果要比索罗精确。

时间: 2024-08-27 06:57:13

SQL点滴20—T-SQL中的排名函数的相关文章

SQL点滴15—在SQL Server 2008中调用C#程序

原文:SQL点滴15-在SQL Server 2008中调用C#程序 T-SQL的在执行普通的查询的时候是很高效的,但是在执行循环,判断这样的语句的时候效率就不那么的高了.这时可以借助CLR了,我们可以在SQL Server 2008中扩展C#程序来完成循环等过程式的查询,或者其他SQL不便实现的功能.这个随笔中将介绍在SQL Server中扩展C#程序实现正则表达式的替换功能. 新建一个类库程序命名为Regex,打开Visual Studio 2008,点击File,点击New,点击Proje

SQL点滴7—使用SQL Server的attach功能出现错误及解决方法

原文:SQL点滴7-使用SQL Server的attach功能出现错误及解决方法 今天用SQL Server 2008的attach功能附加一个数据库,出了点问题,提示的错误是: Unable to open physical file "D:\Documents\Dalt\XXXX.mdf" Operating system error 5: "5(error not found)" (Microsoft SQL Server: Error 5120)"

Sql中Rank排名函数

A.对分区中的行进行排名 以下示例按照数量对指定清单位置的清单中的产品进行了排名. 结果集按 LocationID 分区并在逻辑上按 Quantity 排序. 注意,产品 494 和 495 具有相同的数量. 因为它们是关联的,所以两者均排名第一. USE AdventureWorks2012; GO SELECT i.ProductID, p.Name, i.LocationID, i.Quantity ,RANK() OVER (PARTITION BY i.LocationID ORDER

SQL Server 中的排名函数与使用场景

1.RowNumber() Over (oder by.....)   在需要对某个不连续ID的表进行排序时使用 2.ROW_NUMBER() over(PARTITION by ...... order by ......)  在需要对某个表先进行分区时,再在分区内进行排序操作时使用 3.RANK() over(order by ......) 在需要对某个字段进行同名排序时使用(不考虑并列) 4.DENSE_RANK() over(order by ......) (同上,但是考虑并列名次)

Azure SQL Database (20) 使用SQL Server 2016 Upgrade Advisor

<Windows Azure Platform 系列文章目录> 在上一节中,我们简单介绍了Azure Stretch Database Azure SQL Database (18) Stretch Database 概览 本节将介绍如何使用SQL Server 2016 Upgrade Advisor,评估本地SQL Server 2016数据库的相关数据表,是否可以迁移到Azure SQL Stretch Database里. 本节内容的前提要求: (1)SQL Server 2016 h

你真的会玩SQL吗?表表达式,排名函数

这次讲的有些可能是经常用但不会注意到,所以来统一总结一下用法. 我们往往需要临时存储某些结果集.除了用临时表和表变量,还可以使用公用表表达式的方法. 表表达式 期待单个值的地方可以使用标量子查询 期待多个值的地方可以使用多值子查询 在期待出现表的地方可用表值子查询或表表达式 1.派生表 是从查询表达式派生出虚拟结果表的表表达式,派生表的存在范围只是外部查询. 使用形式:from 派生表 as 派生表列名 规则: 所有列必须有名称 列名必须唯一 不允许使用order by(除非指定了top) 不同

SQL点滴17—使用数据库引擎存储过程,系统视图查询,DBA,BI开发人员必备基础知识

原文:SQL点滴17-使用数据库引擎存储过程,系统视图查询,DBA,BI开发人员必备基础知识 在开发过程中会遇到需要弄清楚这个数据库什么时候建的,这个数据库中有多少表,这个存储过程长的什么样子等等信息,今天把自己工作过程中经常用到的一些数据库引擎存储过程,系统视图等等总结一下以备不时之用.下面的知识多是自己总结,有一些参考了MSDN. sp_help 有时候想尽快查出数据库对象的相关信息,这个存储过程就很有用了.使用它可以查询出整个数据库中所有对象的相关信息.直接运行sp_help结果如下图1,

SQL点滴18—SqlServer中的merge操作,相当地风骚

原文:SQL点滴18-SqlServer中的merge操作,相当地风骚 今天在一个存储过程中看见了merge这个关键字,第一个想法是,这个是配置管理中的概念吗,把相邻两次的更改合并到一起.后来在technet上搜索发现别有洞天,原来是另外一个sql关键字,t-sql的语法还是相当地丰富的.本篇是一篇学习笔记,没有什么新意,这里给出technet上的地址连接供大家参考权威:http://technet.microsoft.com/zh-cn/library/bb510625.aspx,这里具体的语

SQL点滴34—SQL中的大小写

原文:SQL点滴34-SQL中的大小写 默认情况下,SQL Server不区分大小写,如果数据表TEST的TNAME列中有数据“abcd”和“Abcd”, 如果使用查询语句:select * from test  where  tname  like 'a%',则查询的结果会把上面的两条记录都查询出来,这一点上和Oracle有区别. 可以通过设置排序规使其区分大小写,可以分别在创建数据库.修改数据库.创建表的字符型列(char\varchar\nchar \nvarchar等)时指定排序规则来实