4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介

jacklove
リリース: 2018-06-14 16:48:01
オリジナル
6095 人が閲覧しました

ランキング機能はSql Server2005の新機能です。それぞれの使い方と違いを簡単に紹介します。新しい Order テーブルを作成し、効果を確認できるようにいくつかの初期データを追加します。

テーブル構造と初期データSql

テーブル構造と初期データ図を添付します:

4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介

1. ROW _NUMBER

目的of row_number これは、ソートに使用するのが最適です。通常、クエリされたレコードの各行にシリアル番号を生成し、重複することなく順番にソートします。 row_number 関数を使用する場合は、並べ替えてシリアル番号を生成する列を選択する必要があることを確認します。 Row_number の使用例:


select ROW_NUMBER() OVER(order by [SubTime] desc) as row_num,* from [Order]
ログイン後にコピー


クエリ結果は以下のようになります:

4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介

列はによって生成されたシリアル番号列row_number 関数。基本的には、まず over 句の並べ替えステートメントを使用してレコードを並べ替え、次にこの順序でシリアル番号を生成します。 over 句の order by 句は、SQL ステートメントの order by 句とはまったく関係がありません。たとえば、次の SQL では、over 句は次のように配置されます。 SQL ステートメント内で SubTime に従って降順に並べ替えます。 次に、TotalPrice で降順に並べ替えます。


select ROW_NUMBER() OVER(order by [SubTime] desc) as row_num,* from [Order] order by [TotalPrice] desc
ログイン後にコピー


  查询结果如下图所示:

  over子句和sql语句中的order by 可完全不同-晓菜鸟

  利用row_number可以实现web程序的分页,我们来查询指定范围的表数据。例:根据订单提交时间倒序排列获取第三至第五条数据。


with orderSection as(    select ROW_NUMBER() OVER(order by [SubTime] desc) rownum,* from [Order])select * from [orderSection] where rownum between 3 and 5 order by [SubTime] desc
ログイン後にコピー


  查询结果如下图所示:

  4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介

  注意:在使用row_number实现分页时需要特别注意一点,over子句中的order by 要与Sql排序记录中的order by 保持一致,否则得到的序号可能不是连续的。下面我们写一个例子来证实这一点,将上面Sql语句中的排序字段由SubTime改为TotalPrice。另外提一下,对于带有子查询和CTE的查询,子查询和CTE查询有序并不代表整个查询有序,除非显示指定了order by。


with orderSection as(    select ROW_NUMBER() OVER(order by [SubTime] desc) rownum,* from [Order])select * from [orderSection] where rownum between 3 and 5 order by [TotalPrice] desc
ログイン後にコピー


  查询结果如下图所示:

  over子句中的order by 与sql排序的order by 不一致-晓菜鸟

  

二、RANK

  rank函数用于返回结果集的分区内每行的排名, 行的排名是相关行之前的排名数加一。简单来说rank函数就是对查询出来的记录进行排名,与row_number函数不同的是,rank函数考虑到了over子句中排序字段值相同的情况,如果使用rank函数来生成序号,over子句中排序字段值相同的序号是一样的,后面字段值不相同的序号将跳过相同的排名号排下一个,也就是相关行之前的排名数加一,可以理解为根据当前的记录数生成序号,后面的记录依此类推。可能我描述的比较苍白,理解起来也比较吃力,我们直接上代码,rank函数的使用方法与row_number函数完全相同。


select RANK() OVER(order by [UserId]) as rank,* from [Order]
ログイン後にコピー


  查询结果如下图所示:

  4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介

  由上图可以看出,rank函数在进行排名时,同一组的序号是一样的,而后面的则是根据当前的记录数依次类推,图中第一、二条记录的用户Id相同,所以他们的序号是一样的,第三条记录的序号则是3。  

 

三、DENSE_RANK

  dense_rank函数的功能与rank函数类似,dense_rank函数在生成序号时是连续的,而rank函数生成的序号有可能不连续。dense_rank函数出现相同排名时,将不跳过相同排名号,rank值紧接上一次的rank值。在各个分组内,rank()是跳跃排序,有两个第一名时接下来就是第四名,dense_rank()是连续排序,有两个第一名时仍然跟着第二名。将上面的Sql语句改由dense_rank函数来实现。


select DENSE_RANK() OVER(order by [UserId]) as den_rank,* from [Order]
ログイン後にコピー


  查询结果如下图所示:

  4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介

  图中第一、二条记录的用户Id相同,所以他们的序号是一样的,第三条记录的序号紧接上一个的序号,所以为2不为3,后面的依此类推。

四、NTILE

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


select NTILE(4) OVER(order by [SubTime] desc) as ntile,* from [Order]
ログイン後にコピー


  查询结果如下图所示:

  4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介

  Order表的总记录数是6条,而上面的Sql语句ntile函数指定的组数是4,那么Sql Server2005是怎么来决定每一组应该分多少条记录呢?这里我们就需要了解ntile函数的分组依据(约定)。

  ntile函数的分组依据(约定):

  1、每组的记录数不能大于它上一组的记录数,即编号小的桶放的记录数不能小于编号大的桶。也就是说,第1组中的记录数只能大于等于第2组及以后各组中的记录数。

  2、所有组中的记录数要么都相同,要么从某一个记录较少的组(命名为X)开始后面所有组的记录数都与该组(X组)的记录数相同。也就是说,如果有个组,前三组的记录数都是9,而第四组的记录数是8,那么第五组和第六组的记录数也必须是8。

  这里对约定2进行详细说明一下,以便于更好的理解。

  首先系统会去检查能不能对所有满足条件的记录进行平均分组,若能则直接平均分配就完成分组了;若不能,则会先分出一个组,这个组分多少条记录呢?就是 (总记录数/总组数)+1 条,之所以分配 (总记录数/总组数)+1 条是因为当不能进行平均分组时,总记录数%总组数肯定是有余的,又因为分组约定1,所以先分出去的组需要+1条。

  分完之后系统会继续去比较余下的记录数和未分配的组数能不能进行平均分配,若能,则平均分配余下的记录;若不能,则再分出去一组,这个组的记录数也是(总记录数/总组数)+1条。

  然后系统继续去比较余下的记录数和未分配的组数能不能进行平均分配,若能,则平均分配余下的记录;若还是不能,则再分配出去一组,继续比较余下的......这样一直进行下去,直至分组完成。

  举个例子,将51条记录分配成5组,51%5==1不能平均分配,则先分出去一组(51/5)+1=11条记录,然后比较余下的 51-11=40 条记录能否平均分配给未分配的4组,能平均分配,则剩下的4组,每组各40/4=10 条记录,分配完成,分配结果为:11,10,10,10,10,晓菜鸟我开始就错误的以为他会分配成 11,11,11,11,7。

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

 


4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介

//mod表示取余,p表示取整.if(记录总数 mod 桶数==0)
{
  recordCount=记录总数 p 桶数;
  //将每桶的记录数都设为recordCount.}else{
  recordCount1=记录总数 p 桶数+1;
  int n=1;//n表示桶中记录数为recordCount1的最大桶数.  m=recordCount1*n;  while(((记录总数-m) mod (桶数- n)) !=0)
  {
    n++;
    m=recordCount1*n;
  }
  recordCount2=(记录总数-m) p (桶数-n);
  //将前n个桶的记录数设为recordCount1.  //将n+1个至后面所有桶的记录数设为recordCount2.}
ログイン後にコピー

4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介

 

 NTILE()函数算法实现代码

  

  根据上面的算法,如果总记录数为59,总组数为5,则 n=4 , recordCount1=12 , recordCount2=11,分组结果为 :12,12,12,12,11。

  如果总记录数为53,总组数为5,则 n=3 , recordCount1=11 , recordCount2=10,分组结果为:11,11,11,10,10。

  就拿上面的例子来说,总记录数为6,总组数为4,通过算法得到 n=2 , recordCount1=2 , recordCount2=1,分组结果为:2,2,1,1。

 


select ntile,COUNT([ID]) recordCount from (    select NTILE(4) OVER(order by [SubTime] desc) as ntile,* from [Order]) as tgroup by t.ntile
ログイン後にコピー


 

  运行Sql,分组结果如图:

  4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介

  比对算法与Sql Server的分组结果是一致的,说明算法没错。:)

 

总结:

在使用排名函数的时候需要注意以下三点:

1.ランキング関数にはOVER句が必要です。

2. ランキング関数には、ORDER BYを含むOVER句が必要です。

3.グループ内で1から並べ替えます。

この記事では、SQL の 4 つの主要なランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) に関連する知識について説明します。その他の関連コンテンツについては、php 中国語 Web サイトを参照してください。

関連する推奨事項:

Mysql の一般的なベンチマーク ツール

Mysql 関数関連の説明

SQLLite 関連のコンテンツ

以上が4 つの主要な SQL ランキング関数 (ROW_NUMBER、RANK、DENSE_RANK、NTILE) の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
sql
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート