分享好友 最新动态首页 最新动态分类 切换频道
0021 Ms SQL 2005 四个排名函数(row_number、rank、dense_rank 和 ntile)的比较
2024-12-26 22:51

  上面的 SQL 语句的查询结果如图 4 所示。

0021 Ms SQL 2005 四个排名函数(row_number、rank、dense_rank 和 ntile)的比较

                                                                  图 4

  上面的 SQL 语句使用了 CTE,关于 CTE 的介绍将读者参阅《SQL Server 2005 杂谈(1:使用公用表表达式(CTE)简化嵌套 SQL 》。

  另外要注意的是,如果将 row_number 函数用于分页处理,over 子句中的 order by 与排序记录的 order by 应相同,否则生成的序号可能不是有续的。

  当然,不使用 row_number 函数也可以实现查询指定范围的记录,就是比较麻烦。一般的方法是使用颠倒 Top 来实现,例如,查询 t_table 表中第2条和第3条记录,可以先查出前 3 条记录然后将查询出来的这三条记录按倒序排序,再取前 2 条记录,最后再将查出来的这 2 条记录再按倒序排序,就是最终结果。SQL 语句如下

  上面的 SQL 语句查询出来的结果如图 5 所示。

                                                                图 5

  这个查询结果除了没有序号列 row_number,其他的与图 4 所示的查询结果完全一样。

  二、rank

  rank 函数考虑到了 over 子句中排序字段值相同的情况,为了更容易说明问题,在 t_table 表中再加一条记录,如图 6 所示。

                                                                    图 6

  在图 6 所示的记录中后三条记录的 field1 字段值是相同的。如果使用 rank 函数来生成序号,这 3 条记录的序号是相同的,而第 4 条记录会根据当前的记录数生成序号,后面的记录依此类推,也就是说,在这个例子中,第 4 条记录的序号是 4,而不是 2。rank 函数的使用方法与 row_number 函数完全相同,SQL 语句如下

  上面的 SQL 语句的查询结果如图 7 所示。

                                                                           图 7

  三、dense_rank

  dense_rank 函数的功能与 rank 函数类似,只是在生成序号时是连续的,而 rank 函数生成的序号有可能不连续。如上面的例子中如果使用 dense_rank 函数,第 4 条记录的序号应该是 2,而不是 4。如下面的 SQL 语句所示

  上面的 SQL 语句的查询结果如图 8 所示。

                                                                       图 8

  读者可以比较图 7 和图 8 所示的查询结果有什么不同

  四、ntile

  ntile 函数可以对序号进行分组处理。这就相当于将查询出来的记录集放到指定长度的数组中,每一个数组元素存放一定数量的记录。ntile 函数为每条记录生成的序号就是这条记录所有的数组元素的索引(从 1 开始)。也可以将每一个分配记录的数组元素称为“桶”。ntile 函数有一个参数,用来指定桶数。下面的 SQL 语句使用 ntile 函数对 t_table 表进行了装桶处理

  上面的 SQL 语句的查询结果如图 9 所示。

                                                                       图 9

  由于 t_table 表的记录总数是 6,而上面的 SQL 语句中的 ntile 函数指定了桶数为 4。

  也许有的读者会问这么一个问题,SQL Server 2005 怎么来决定某一桶应该放多少记录呢?可能 t_table 表中的记录数有些少,那么我们假设 t_table 表中有 59 条记录,而桶数是 5,那么每一桶应放多少记录呢

  实际上通过两个约定就可以产生一个算法来决定哪一个桶应放多少记录,这两个约定如下

  1. 编号小的桶放的记录不能小于编号大的桶。也就是说,第 1 捅中的记录数只能大于等于第 2 桶及以后的各桶中的记录。

    2. 所有桶中的记录要么都相同,要么从某一个记录较少的桶开始后面所有捅的记录数都与该桶的记录数相同。也就是说,如果有个桶,前三桶的记录数都是 10,而第 4 捅的记录数是 6,那么第 5 桶和第 6 桶的记录数也必须是 6。

  根据上面的两个约定,可以得出如下的算法

  根据上面的算法,如果记录总数为 59,桶数为 5,则前 4 个桶的记录数都是 12,最后一个桶的记录数是 11。

  如果记录总数为 53,桶数为 5,则前 3 个桶的记录数为 11,后 2 个桶的记录数为 10。

  就拿本例来说,记录总数为 6,桶数为 4,则会算出 recordCount1 的值为 2,在结束 while 循环后,会算出 recordCount2 的值是 1,因此,前 2 个桶的记录是 2,后 2 个桶的记录是 1。

      ROW_NUMBER、RANK、DENSE_RANK 和 NTILE,这些新函数使您可以有效地分析数据以及向查询的结果行提供排序值。您可能发现这些新函数有用的典型方案包括:将连续整数分配给结果行,以便进行表示、分页、计分和绘制直方图。

Speaker Statistics 方案

下面的 Speaker Statistics 方案将用来讨论和演示不同的函数和它们的子句。大型计算会议包括三个议题:数据库、开发和系统管理。十一位演讲者在会议中发表演讲,并且为他们的讲话获得 范围为 1 到 9 的分数。结果被总结并存储在下面的 SpeakerStats 表中

CREATE TABLE SpeakerStats( 
    speaker        VARCHAR(10) NOT NULL PRIMARY KEY
    , track          VARCHAR(10) NOT NULL
    , score          INT         NOT NULL
    , pctfilledevals INT         NOT NULL
    , numsessions    INT         NOT NULL)

SET NOCOUNT ON

INSERT INTO SpeakerStats VALUES('Dan',     'Sys', 3, 22, 4)
INSERT INTO SpeakerStats VALUES('Ron',     'Dev', 9, 30, 3)
INSERT INTO SpeakerStats VALUES('Kathy',   'Sys', 8, 27, 2)
INSERT INTO SpeakerStats VALUES('Suzanne', 'DB', 9, 30, 3)
INSERT INTO SpeakerStats VALUES('Joe',     'Dev', 6, 20, 2)
INSERT INTO SpeakerStats VALUES('Robert', 'Dev', 6, 28, 2)
INSERT INTO SpeakerStats VALUES('Mike',    'DB', 8, 20, 3)
INSERT INTO SpeakerStats VALUES('Michele', 'Sys', 8, 31, 4)
INSERT INTO SpeakerStats VALUES('Jessica', 'Dev', 9, 19, 1)
INSERT INTO SpeakerStats VALUES('Brian',   'Sys', 7, 22, 3)
INSERT INTO SpeakerStats VALUES('Kevin',   'DB', 7, 25, 4)

每个演讲者都在该表中具有一个行,其中含有该演讲者的名字、议题、平均得分、填写评价的与会者相对于参加会议的与会者数量的百分比以及该演讲者发表演讲的次数。本节演示如何使用新的排序函数分析演讲者统计数据以生成有用的信息。

ROW_NUMBER

ROW_NUMBER 函数使您可以向查询的结果行提供连续的整数值。例如,假设您要返回所有演讲者的 speaker、track 和 score,同时按照 score 降序向结果行分配从 1 开始的连续值。以下查询通过使用 ROW_NUMBER 函数并指定 OVER (ORDER BY score DESC) 生成所需的结果

SELECT ROW_NUMBER() OVER(ORDER BY score DESC) AS rownum,   speaker, track, scoreFROM SpeakerStatsORDER BY score DESC 以下为结果集

rownum speaker    track      score
------ ---------- ---------- -----------
1      Jessica    Dev        9
2      Ron        Dev        9
3      Suzanne    DB         9
4      Kathy      Sys        8
5      Michele    Sys        8
6      Mike       DB         8
7      Kevin      DB         7
8      Brian      Sys        7
9      Joe        Dev        6
10     Robert     Dev        6
11     Dan        Sys        3
得 分最高的演讲者获得行号 1,得分最低的演讲者获得行号 11。ROW_NUMBER 总是按照请求的排序为不同的行生成不同的行号。请注意,如果在 OVER() 选项中指定的 ORDER BY 列表不唯一,则结果是不确定的。这意味着该查询具有一个以上正确的结果;在该查询的不同调用中,可能获得不同的结果。例如,在我们的示例中,有三个不同的 演讲者获得相同的最高得分 (9):Jessica、Ron 和 Suzanne。由于 SQL Server 必须为不同的演讲者分配不同的行号,因此您应当假设分别分配给 Jessica、Ron 和 Suzanne 的值 1、2 和 3 是按任意顺序分配给这些演讲者的。如果值 1、2 和 3 被分别分配给 Ron、Suzanne 和 Jessica,则结果应该同样正确。

如 果您指定一个唯一的 ORDER BY 列表,则结果总是确定的。例如,假设在演讲者之间出现得分相同的情况时,您希望使用最高的 pctfilledevals 值来分出先后。如果值仍然相同,则使用最高的 numsessions 值来分出先后。最后,如果值仍然相同,则使用最低词典顺序 speaker 名字来分出先后。由于 ORDER BY 列表 — score、pctfilledevals、numsessions 和 speaker — 是唯一的,因此结果是确定的

SELECT ROW_NUMBER() OVER(ORDER BY score DESC, pctfilledevals DESC,  numsessions DESC, speaker) AS rownum,   speaker, track, score, pctfilledevals, numsessions FROM SpeakerStats ORDER BY score DESC, pctfilledevals DESC, numsessions DESC, speaker 以下为结果集

rownum speaker    track      score       pctfilledevals numsessions
------ ---------- ---------- ----------- -------------- -----------
1      Ron        Dev        9           30             3
2      Suzanne    DB         9           30             3
3      Jessica    Dev        9           19             1
4      Michele    Sys        8           31             4
5      Kathy      Sys        8           27             2
6      Mike       DB         8           20             3
7      Kevin      DB         7           25             4
8      Brian      Sys        7           22             3
9      Robert     Dev        6           28             2
10     Joe        Dev        6           20             2
11     Dan        Sys        3           22             4
新的排序函数的重要好处之一是它们的效率。SQL Server 的优化程序只需要扫描数据一次,以便计算值。它完成该工作的方法是:使用在排序列上放置的索引的有序扫描,或者,如果未创建适当的索引,则扫描数据一次并对其进行排序。

另一个好处是语法的简单性。为了让您感受一下通过使用在 SQL Server 的较低版本中采用的基于集的方法来计算排序值是多么困难和低效,请考虑下面的 SQL Server 2000 查询,它返回与上一个查询相同的结果
SELECT (SELECT COUNT(*)   FROM SpeakerStats AS S2   
            WHERE S2.score > S1.score     
            OR (S2.score = S1.score  AND S2.pctfilledevals > S1.pctfilledevals)     
            OR (S2.score = S1.score  AND S2.pctfilledevals = S1.pctfilledevals  AND S2.numsessions > S1.numsessions)     
            OR (S2.score = S1.score  AND S2.pctfilledevals = S1.pctfilledevals  AND S2.numsessions = S1.numsessions  AND S2.speaker < S1.speaker)
            ) + 1 AS rownum
            , speaker, track, score, pctfilledevals, numsessions 
            FROM SpeakerStats AS S1 
            ORDER BY score DESC, pctfilledevals DESC, numsessions DESC, speaker

该查询显然比 SQL Server 2005 查询复杂得多。此外,对于 SpeakerStats 表中的每个基础行,SQL Server 都必须扫描该表的另一个实例中的所有匹配行。对于基础表中的每个行,平均大约需要扫描该表的一半(最少)行。SQL Server 2005 查询的性能恶化是线性的,而 SQL Server 2000 查询的性能恶化是指数性的。即使是在相当小的表中,性能差异也是显著的。

行号的一个典型应用是通过查询结果分页。给定页大小(以行数为单位)和页号,需要返回属于给定页的行。例如,假设您希望按照 “score DESC, speaker” 顺序从 SpeakerStats 表中返回第二页的行,并且假定页大小为三行。下面的查询首先按照指定的排序计算派生表 D 中的行数,然后只筛选行号为 4 到 6 的行(它们属于第二页

SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY score DESC, speaker) AS rownum, speaker, track, score FROM SpeakerStats) AS D
WHERE rownum BETWEEN 4 AND 6 ORDER BY score DESC, speaker

以下为结果集

rownum speaker    track      score
------ ---------- ---------- -----------
4      Kathy      Sys        8
5      Michele    Sys        8
6      Mike       DB         8
用更一般的术语表达就是,给定 @pagenum 变量中的页号和 @pagesize 变量中的页大小,以下查询返回属于预期页的行
DECLARE @pagenum AS INT, @pagesize AS INT
SET @pagenum = 2
SET @pagesize = 3
SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY score DESC, speaker) AS rownum
                ,speaker
                , track
                , score 
                FROM SpeakerStats) 
                AS DWHERE rownum BETWEEN (@pagenum-1)*@pagesize+1 AND @pagenum*@pagesize 
                ORDER BY score DESC, speaker

上述方法对于您只对行的一个特定页感兴趣的特定请求而言已经足够了。但是,当用户发出多个请求时,该方法就不能满足需要了,因为该查询的每个调用都 需要您对表进行完整扫描,以便计算行号。当用户可能反复请求不同的页时,为了更有效地进行分页,请首先用所有基础表行(包括计算得到的行号)填充一个临时 表,并且对包含这些行号的列进行索引

SELECT ROW_NUMBER() OVER(ORDER BY score DESC, speaker) AS rownum, *
INTO #SpeakerStatsRN
FROM SpeakerStats
CREATE UNIQUE CLUSTERED INDEX idx_uc_rownum ON #SpeakerStatsRN(rownum)

然后,对于所请求的每个页,发出以下查询

SELECT rownum, speaker, track, score
FROM #SpeakerStatsRN
WHERE rownum BETWEEN (@pagenum-1)*@pagesize+1 AND @pagenum*@pagesize
ORDER BY score DESC, speaker

只有属于预期页的行才会被扫描。

分段可以在行组内部独立地计算排序值,而不是为作为一个组的所有表行计算排序值。为此,请使用 PARTITION BY 子句,并且指定一个表达式列表,以标识应该为其独立计算排序值的行组。例如,以下查询按照 “score DESC, speaker” 顺序单独分配每个 track 内部的行号

SELECT track, 
ROW_NUMBER() OVER(
    PARTITION BY track 
    ORDER BY score DESC, speaker) AS pos, 
speaker, score
FROM SpeakerStats
ORDER BY track, score DESC, speaker

以下为结果集

track      pos speaker    score
---------- --- ---------- -----------
DB         1   Suzanne    9
DB         2   Mike       8
DB         3   Kevin      7
Dev        1   Jessica    9
Dev        2   Ron        9
Dev        3   Joe        6
Dev        4   Robert     6
Sys        1   Kathy      8
Sys        2   Michele    8
Sys        3   Brian      7
Sys        4   Dan        3
在 PARTITION BY 子句中指定 track 列会使得为具有相同 track 的每个行组单独计算行号。

RANK, DENSE_RANK

RANK 和 DENSE_RANK 函数非常类似于 ROW_NUMBER 函数,因为它们也按照指定的排序提供排序值,而且可以根据需要在行组(分段)内部提供。但是,与 ROW_NUMBER 不同的是,RANK 和 DENSE_RANK 向在排序列中具有相同值的行分配相同的排序。当 ORDER BY 列表不唯一,并且您不希望为在 ORDER BY 列表中具有相同值的行分配不同的排序时,RANK 和 DENSE_RANK 很有用。RANK 和 DENSE_RANK 的用途以及两者之间的差异可以用示例进行最好的解释。以下查询按照 score DESC 顺序计算不同演讲者的行号、排序和紧密排序值

SELECT speaker, track, score,
ROW_NUMBER() OVER(ORDER BY score DESC) AS rownum,
RANK() OVER(ORDER BY score DESC) AS rnk,
DENSE_RANK() OVER(ORDER BY score DESC) AS drnk
FROM SpeakerStats
ORDER BY score DESC

以下为结果集

speaker    track      score       rownum rnk drnk
---------- ---------- ----------- ------ --- ----
Jessica    Dev        9           1      1   1
Ron        Dev        9           2      1   1
Suzanne    DB         9           3      1   1
Kathy      Sys        8           4      4   2
Michele    Sys        8           5      4   2
Mike       DB         8           6      4   2
Kevin      DB         7           7      7   3
Brian      Sys        7           8      7   3
Joe        Dev        6           9      9   4
Robert     Dev        6           10     9   4
Dan        Sys        3           11     11 5
正 如前面讨论的那样,score 列不唯一,因此不同的演讲者可能具有相同的得分。行号确实代表下降的 score 顺序,但是具有相同得分的演讲者仍然获得不同的行号。但是请注意,在结果中,所有具有相同得分的演讲者都获得相同的排序和紧密排序值。换句话说,当 ORDER BY 列表不唯一时,ROW_NUMBER 是不确定的,而 RANK 和 DENSE_RANK 总是确定的。排序值和紧密排序值之间的差异在于,排序代表:具有较高得分的行号加 1,而紧密排序代表:具有明显较高得分的行号加 1。从您迄今为止已经了解的内容中,您可以推导出当 ORDER BY 列表唯一时,ROW_NUMBER、RANK 和 DENSE_RANK 产生完全相同的值。

NTILE

NTILE 使您可以按照指定的顺序,将查询的结果行分散到指定数量的组 (tile) 中。每个行组都获得不同的号码:第一组为 1,第二组为 2,等等。您可以在函数名称后面的括号中指定所请求的组号,在 OVER 选项的 ORDER BY 子句中指定所请求的排序。组中的行数被计算为 total_num_rows / num_groups。如果有余数 n,则前面 n 个组获得一个附加行。因此,可能不会所有组都获得相等数量的行,但是组大小最大只可能相差一行。例如,以下查询按照 score 降序将三个组号分配给不同的 speaker 行

SELECT speaker, track, score,
ROW_NUMBER() OVER(ORDER BY score DESC) AS rownum,
NTILE(3) OVER(ORDER BY score DESC) AS tile
FROM SpeakerStats
ORDER BY score DESC

以下为结果集

speaker    track      score       rownum tile
---------- ---------- ----------- ------ ----
Jessica    Dev        9           1      1
Ron        Dev        9           2      1
Suzanne    DB         9           3      1
Kathy      Sys        8           4      1
Michele    Sys        8           5      2
Mike       DB         8           6      2
Kevin      DB         7           7      2
Brian      Sys        7           8      2
Joe        Dev        6           9      3
Robert     Dev        6           10     3
Dan        Sys        3           11     3
在 SpeakerStats 表中有 11 位演讲者。将 11 除以 3 得到组大小 3 和余数 2,这意味着前面 2 个组将获得一个附加行(每个组中有 4 行,而第三个组则不会得到附加行(该组中有 3 行)。组号(tile 号)1 被分配给行 1 到 4,组号 2 被分配给行 5 到 8,组号 3 被分配给行 9 到 11。通过该信息可以生成直方图,并且将项目均匀分布到每个梯级。在我们的示例中,第一个梯级表示具有最高得分的演讲者,第二个梯级表示具有中等得分的演 讲者,第三个梯级表示具有最低得分的演讲者。可以使用 CASE 表达式为组号提供说明性的有意义的备选含义

SELECT speaker, track, score,
CASE NTILE(3) OVER(ORDER BY score DESC)
    WHEN 1 THEN 'High'
    WHEN 2 THEN 'Medium'
    WHEN 3 THEN 'Low'
END AS scorecategory
FROM SpeakerStats
ORDER BY track, speaker
以下为结果集

speaker    track      score       scorecategory
---------- ---------- ----------- -------------
Kevin      DB         7           Medium
Mike       DB         8           Medium
Suzanne    DB         9           High
Jessica    Dev        9           High
Joe        Dev        6           Low
Robert     Dev        6           Low
Ron        Dev        9           High
Brian      Sys        7           Medium
Dan        Sys        3           Low
Kathy      Sys        8           High
Michele    Sys        8           Medium

最新文章
MySQL的索引是什么?怎么优化?
索引类似大学图书馆建书目索引,可以提高数据检索的效率,降低数据库的IO成本。MySQL在300万条记录左右性能开始逐渐下降,虽然官方文档说500~800w记录,所以大数据量建立索引是非常有必要的。MySQL提供了Explain,用于显示SQL执行的详细信
新手也能做抖音推文+文生动漫视频!几款AI小程序搞定!
1智能二创工具这款微信小程序专注于视频去重功能。只需轻轻一点“视频去重”的按钮,然后输入视频的链接,或者将原视频上传到小程序,挑选一款你钟爱的模式,即可生成原创视频。2动画推文神器每次在刷抖音的时候,我都会被那些丰富多彩的小
日照SEO
一、SEO是搜索引擎优化(Search Engine Optimization)的英文缩写,中文译为“搜索引擎优化”。SEO是通过优化网站结构、内容和链接等方式来提高网站在搜索引擎中的排名。SEO目的是让其在行业内占据领先地位,获得品牌收益。在一定程度上是
鹿泉SEO赋能,企业网络营销新启航
鹿泉SEO专注于企业网络营销,通过专业策略助力企业抢占数字时代先机,实现品牌价值提升与市场拓展,开启网络营销新篇章。随着互联网的飞速发展,已经成为企业拓展市场、提升品牌知名度的重要手段,(搜索引擎优化)作为网络营销的核心技术
万宁四居室楼盘热搜榜揭晓,第一名竟如此受追捧!
二、万宁四居室热搜楼盘榜单 根据房天下研究院的数据,截至今日,万宁四居室热搜楼盘的名单已经公布,其中包括中海神州半岛、华润·石梅湾九里、海云轩、南洋印象和海南臻园五大楼盘,而中海神州半岛以其绝对优势稳居榜首。| 排名 | 楼盘名
拷贝漫画官方正版2024软件介绍
拷贝漫画官方正版2024下载通过整合多个平台的漫画资源,为用户提供了一个集大成者的阅读平台。这意味着用户无需在多个应用或网站之间跳转,即可轻松找到并阅读自己喜欢的漫画作品,极大地提升了阅读效率和便捷性。该应用涵盖了各种类型的漫
独家 | 生成式AI的设计模式:一份全面的指南
作者:Vincent Koc翻译:高翊之校对:陈超本文约3000字,建议阅读6分钟运用大语言模型(LLM’s)的参考架构模式和心智模型。标签:生成式AI设计模式AI模式的需求在创建新事物的时候,我们都会依赖经过尝试检验的方法、途经和模式。这个说法
新上汽大众帕萨特与速派的区别是什么
新上汽与有不少区别。 外观设计上帕萨特延续大众稳重大气风格融入时尚元素更显年轻动感速派简洁大气线条流畅有力量感。 车身尺寸方面帕萨特为 4933 毫米、1836 毫米、1469 毫米轴距 2871 毫米速派是 4869 毫米、1865 毫米、1489 毫米轴距 2
二房东转租合同范本,二房东转租合同怎么写才有效
在没有事先约定的情况下,租客转租房屋必须经过房东同意,未经房东同意而擅自转租的,房东有权解除合同。对给第三方租客造成的损失,由转租者承担。甲、乙双方就房屋租赁事宜,达成如下协议:甲方将位于xx市xx街道xx小区x号楼xxxx号的房屋
游戏服务器开发岗位职责
岗位职责:1、负责游戏服务器架构的搭建/优化,核心模块开发以及技术攻关;2、迅速响应并解决游戏开发过程中及线上出现的问题,与运维团队紧密合作,确保游戏服务器的稳定运行;3、实时监控服务器性能,针对游戏性能及稳定性进行调优,提升
相关文章
推荐文章
发表评论
0评