當前位置:首頁 > 芯聞號 > 充電吧
[導讀]排名函數是Sql Server2005新增的功能,下面簡單介紹一下他們各自的用法和區(qū)別。我們新建一張Order表并添加一些初始數據方便我們查看效果。?CREATE?TABLE?[dbo].[Order


排名函數是Sql Server2005新增的功能,下面簡單介紹一下他們各自的用法和區(qū)別。我們新建一張Order表并添加一些初始數據方便我們查看效果。

?

CREATE?TABLE?[dbo].[Order](
????[ID]?[int]?IDENTITY(1,1)?NOT?NULL,
????[UserId]?[int]?NOT?NULL,
????[TotalPrice]?[int]?NOT?NULL,
????[SubTime]?[datetime]?NOT?NULL,
?CONSTRAINT?[PK_Order]?PRIMARY?KEY?CLUSTERED?
(
????[ID]?ASC
)WITH?(PAD_INDEX?=?OFF,?STATISTICS_NORECOMPUTE?=?OFF,?IGNORE_DUP_KEY?=?OFF,?ALLOW_ROW_LOCKS?=?ON,?ALLOW_PAGE_LOCKS?=?ON)?ON?[PRIMARY]
)?ON?[PRIMARY]

GO
SET?IDENTITY_INSERT?[dbo].[Order]?ON?

GO
INSERT?[dbo].[Order]?([ID],?[UserId],?[TotalPrice],?[SubTime])?VALUES?(1,?1,?100,?CAST(0x0000A419011D32AF?AS?DateTime))
GO
INSERT?[dbo].[Order]?([ID],?[UserId],?[TotalPrice],?[SubTime])?VALUES?(2,?2,?500,?CAST(0x0000A419011D40BA?AS?DateTime))
GO
INSERT?[dbo].[Order]?([ID],?[UserId],?[TotalPrice],?[SubTime])?VALUES?(3,?3,?300,?CAST(0x0000A419011D4641?AS?DateTime))
GO
INSERT?[dbo].[Order]?([ID],?[UserId],?[TotalPrice],?[SubTime])?VALUES?(4,?2,?1000,?CAST(0x0000A419011D4B72?AS?DateTime))
GO
INSERT?[dbo].[Order]?([ID],?[UserId],?[TotalPrice],?[SubTime])?VALUES?(5,?1,?520,?CAST(0x0000A419011D50F3?AS?DateTime))
GO
INSERT?[dbo].[Order]?([ID],?[UserId],?[TotalPrice],?[SubTime])?VALUES?(6,?2,?2000,?CAST(0x0000A419011E50C9?AS?DateTime))
GO
SET?IDENTITY_INSERT?[dbo].[Order]?OFF
GO
ALTER?TABLE?[dbo].[Order]?ADD??CONSTRAINT?[DF_Order_SubTime]??DEFAULT?(getdate())?FOR?[SubTime]
GO

?

?

  附上表結構和初始數據圖:

  

?

一、ROW_NUMBER

  row_number的用途的非常廣泛,排序最好用他,一般可以用來實現web程序的分頁,他會為查詢出來的每一行記錄生成一個序號,依次排序且不會重復,注意使用row_number函數時必須要用over子句選擇對某一列進行排序才能生成序號。row_number用法實例:

?

select?ROW_NUMBER()?OVER(order?by?[SubTime]?desc)?as?row_num,*?from?[Order]

?

  查詢結果如下圖所示:

  

  圖中的row_num列就是row_number函數生成的序號列,其基本原理是先使用over子句中的排序語句對記錄進行排序,然后按照這個順序生成序號。over子句中的order by子句與SQL語句中的order by子句沒有任何關系,這兩處的order by 可以完全不同,如以下sql,over子句中根據SubTime降序排列,Sql語句中則按TotalPrice降序排列。

select?ROW_NUMBER()?OVER(order?by?[SubTime]?desc)?as?row_num,*?from?[Order]?order?by?[TotalPrice]?desc

  查詢結果如下圖所示:

  

  利用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

  查詢結果如下圖所示:

  

  注意:在使用row_number實現分頁時需要特別注意一點,over子句中的order by 要與Sql排序記錄中的order by 保持一致,否則得到的序號可能不是連續(xù)的。下面我們寫一個例子來證實這一點,將上面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

  查詢結果如下圖所示:

  

  

二、RANK

  rank函數用于返回結果集的分區(qū)內每行的排名,?行的排名是相關行之前的排名數加一。簡單來說rank函數就是對查詢出來的記錄進行排名,與row_number函數不同的是,rank函數考慮到了over子句中排序字段值相同的情況,如果使用rank函數來生成序號,over子句中排序字段值相同的序號是一樣的,后面字段值不相同的序號將跳過相同的排名號排下一個,也就是相關行之前的排名數加一,可以理解為根據當前的記錄數生成序號,后面的記錄依此類推。可能我描述的比較蒼白,理解起來也比較吃力,我們直接上代碼,rank函數的使用方法與row_number函數完全相同。

select?RANK()?OVER(order?by?[UserId])?as?rank,*?from?[Order]

  查詢結果如下圖所示:

  

  由上圖可以看出,rank函數在進行排名時,同一組的序號是一樣的,而后面的則是根據當前的記錄數依次類推,圖中第一、二條記錄的用戶Id相同,所以他們的序號是一樣的,第三條記錄的序號則是3?! ?/p>

?

三、DENSE_RANK

  dense_rank函數的功能與rank函數類似,dense_rank函數在生成序號時是連續(xù)的,而rank函數生成的序號有可能不連續(xù)。dense_rank函數出現相同排名時,將不跳過相同排名號,rank值緊接上一次的rank值。在各個分組內,rank()是跳躍排序,有兩個第一名時接下來就是第四名,dense_rank()是連續(xù)排序,有兩個第一名時仍然跟著第二名。將上面的Sql語句改由dense_rank函數來實現。

select?DENSE_RANK()?OVER(order?by?[UserId])?as?den_rank,*?from?[Order]

  查詢結果如下圖所示:

  

  圖中第一、二條記錄的用戶Id相同,所以他們的序號是一樣的,第三條記錄的序號緊接上一個的序號,所以為2不為3,后面的依此類推。

四、NTILE

  ntile函數可以對序號進行分組處理,將有序分區(qū)中的行分發(fā)到指定數目的組中。?各個組有編號,編號從一開始。?對于每一個行,ntile 將返回此行所屬的組的編號。這就相當于將查詢出來的記錄集放到指定長度的數組中,每一個數組元素存放一定數量的記錄。ntile函數為每條記錄生成的序號就是這條記錄所有的數組元素的索引(從1開始)。也可以將每一個分配記錄的數組元素稱為“桶”。ntile函數有一個參數,用來指定桶數。下面的SQL語句使用ntile函數對Order表進行了裝桶處理:

select?NTILE(4)?OVER(order?by?[SubTime]?desc)?as?ntile,*?from?[Order]

  查詢結果如下圖所示:

  

  Order表的總記錄數是6條,而上面的Sql語句ntile函數指定的組數是4,那么Sql Server2005是怎么來決定每一組應該分多少條記錄呢?這里我們就需要了解ntile函數的分組依據(約定)。

  ntile函數的分組依據(約定):

  1、每組的記錄數不能大于它上一組的記錄數,即編號小的桶放的記錄數不能小于編號大的桶。也就是說,第1組中的記錄數只能大于等于第2組及以后各組中的記錄數。

  2、所有組中的記錄數要么都相同,要么從某一個記錄較少的組(命名為X)開始后面所有組的記錄數都與該組(X組)的記錄數相同。也就是說,如果有個組,前三組的記錄數都是9,而第四組的記錄數是8,那么第五組和第六組的記錄數也必須是8。

  這里對約定2進行詳細說明一下,以便于更好的理解。

  首先系統(tǒng)會去檢查能不能對所有滿足條件的記錄進行平均分組,若能則直接平均分配就完成分組了;若不能,則會先分出一個組,這個組分多少條記錄呢?就是 (總記錄數/總組數)+1 條,之所以分配 (總記錄數/總組數)+1 條是因為當不能進行平均分組時,總記錄數%總組數肯定是有余的,又因為分組約定1,所以先分出去的組需要+1條。

  分完之后系統(tǒng)會繼續(xù)去比較余下的記錄數和未分配的組數能不能進行平均分配,若能,則平均分配余下的記錄;若不能,則再分出去一組,這個組的記錄數也是(總記錄數/總組數)+1條。

  然后系統(tǒng)繼續(xù)去比較余下的記錄數和未分配的組數能不能進行平均分配,若能,則平均分配余下的記錄;若還是不能,則再分配出去一組,繼續(xù)比較余下的......這樣一直進行下去,直至分組完成。

  舉個例子,將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。

  根據上面的兩個約定,可以得出如下的算法:

?

//mod表示取余,div表示取整.
if(記錄總數?mod?桶數==0)
{
  recordCount=記錄總數?div?桶數;
  //將每桶的記錄數都設為recordCount.
}
else
{
  recordCount1=記錄總數?div?桶數+1;
  int?n=1;//n表示桶中記錄數為recordCount1的最大桶數.
  m=recordCount1*n;
  while(((記錄總數-m) mod (桶數- n)) !=0)
  {
    n++;
    m=recordCount1*n;
  }
  recordCount2=(記錄總數-m)?div (桶數-n);
  //將前n個桶的記錄數設為recordCount1.
  //將n+1個至后面所有桶的記錄數設為recordCount2.
}

?

?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?t
group?by?t.ntile

?

  運行Sql,分組結果如圖:

  

  比對算法與Sql Server的分組結果是一致的,說明算法沒錯。:)

?

總結:

在使用排名函數的時候需要注意以下三點:

  1、排名函數必須有?OVER?子句。

  2、排名函數必須有包含 ORDER BY 的 OVER 子句。

  3、分組內從1開始排序。


本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯系該專欄作者,如若文章內容侵犯您的權益,請及時聯系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或將催生出更大的獨角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數字化轉型技術解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關鍵字: AWS AN BSP 數字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術公司SODA.Auto推出其旗艦產品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關鍵字: 汽車 人工智能 智能驅動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據媒體報道,騰訊和網易近期正在縮減他們對日本游戲市場的投資。

關鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數據產業(yè)博覽會開幕式在貴陽舉行,華為董事、質量流程IT總裁陶景文發(fā)表了演講。

關鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數據產業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數字世界的話語權最終是由生態(tài)的繁榮決定的。

關鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經營業(yè)績穩(wěn)中有升 落實提質增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領增長 以科技創(chuàng)新為引領,提升企業(yè)核心競爭力 堅持高質量發(fā)展策略,塑強核心競爭優(yōu)勢...

關鍵字: 通信 BSP 電信運營商 數字經濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術學會聯合牽頭組建的NVI技術創(chuàng)新聯盟在BIRTV2024超高清全產業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現場 NVI技術創(chuàng)新聯...

關鍵字: VI 傳輸協議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯合招商會上,軟通動力信息技術(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關鍵字: BSP 信息技術
關閉
關閉