1. 程式人生 > >SQL Server排名函式與排名開窗函式

SQL Server排名函式與排名開窗函式

什麼是排名函式?說實話我也不甚清楚,我知道 order by 是排序用的,那麼什麼又是排名函式呢?

接下來看幾個示例就明白了。

首先建立一個表,隨便插入一些資料。

ROW_NUMBER 函式:直接排序,ROW_NUMBER函式是以上升進行直接排序,並且以連續的順序給每一行資料一個唯一的序號。(即排名連續)

1 -- 以下是根據 U_Pwd 這一列進行排名(升序)
2 select *,
3 '第'+convert(varchar,ROW_NUMBER() over(order by U_Pwd))+'名' RowNum
4 from UserInfo

RANK 函式:並列排序,

在 order by 子句中指定的列,如果返回一行資料與另一行具有相同的值,rank函式將給這些行賦予相同的排名數值。

在排名的過程中,保持一個內部計數值,當值有所改變時,排名序號將有一個跳躍。(即排名不連續)

1 -- 以下是根據 U_Pwd 這一列進行排名(升序)
2 select *,
3 '第 '+convert(varchar,rank() over(order by U_Pwd))+' 名' RowNum
4 from UserInfo

可以明確的看到有4行資料並列第2名,然後直接就是第6名,這是因為 order by 子句中指定的列 U_Pwd 的值相同。

DENSE_RANK 函式:並列排序,

這一點與 RANK() 函式類似,order by 子句指定的列的值相同,排名數值相同,但是後面是連續的。(即排名連續)

1 -- 以下是根據 U_Pwd 這一列進行排名(升序)
2 select *,
3 '第 '+convert(varchar,DENSE_RANK() over(order by U_Pwd))+' 名' RowNum
4 from UserInfo

可以看到即使有4行資料並列第2名,但是接下來依然是第3名。

NTILE 函式:將查詢的結果分發到指定數量的組中。 各個組有編號,編號從1開始。 對於每一行,NTILE 將返回此行所屬的組的編號。

組中的行數計算方式為 total_num_rows(結果集的總行數) / num_groups(指定的組數)。

如果有餘數 n,則前面 n 個組獲得一個附加行。因此,可能不會所有組都獲得相等數量的行,但是組大小最大隻可能相差一行。

例如,如果總行數是 53,組數是 5,53 / 5 等於10餘數是3,按上面個規則就是,每組分配10行,又因餘數為3,所以前面3組每組附加一行。

則前三個組每組包含 11 行,其餘兩個組每組包含 10 行。

另一方面,如果總行數可被組數整除,則行數將在組之間平均分佈。 例如,如果總行數為 50,有五個組,則每組將包含 10 行。

1 -- 以下是根據 U_Pwd 這一列進行分組
2 select *,
3 '第 '+convert(varchar,NTILE(3) over(order by U_Pwd))+' 組' RowNum
4 from UserInfo

這個表中有10條資料,指定分為3組,10/3等於3餘數1。

PS:排名函式後面必須有 over() 子句。

 

排名開窗函式:

ROW_NUMBER、DENSE_RANK、RANK、NTILE屬於排名函式,OVER()就是視窗函式。

視窗函式OVER()指定一組行,開窗函式計算從視窗函式輸出的結果集中各行的值。

開窗函式不需要使用GROUP BY就可以對資料進行分組,還可以同時返回基礎行的列和聚合列。

排名開窗函式可以單獨使用ORDER BY 語句,也可以和PARTITION BY同時使用。

ODER BY 指定排名開窗函式的順序。在排名開窗函式中必須使用ORDER BY語句。

PARTITION BY用於將結果集進行分組,開窗函式應用於每一組。

1 -- 以下是先根據 U_Pwd 這一列進行分組,然後每一組再根據 U_Pwd 排序
2 select *,
3 '第'+convert(varchar,ROW_NUMBER() over(partition by U_Pwd order by U_Pwd))+'名' RowNum
4 from UserInfo

因為 U_Pwd 這一列有4種不同的值,所以分為4組,然後 ROW_NUMBER 再在每一組中進行連續排序。

 

1 -- 以下是先根據 U_Pwd 這一列進行分組,然後每一組再根據 U_Pwd 排序
2 select *,
3 '第'+convert(varchar,rank() over(partition by U_Pwd order by U_Pwd))+'名' RowNum
4 from UserInfo

因為 U_Pwd 這一列有4種不同的值,所以同樣是分為4組,然後 RANK 再在每一組中進行排序,因為RANK是並列排序,所以全部都是第一名。下面換個欄位排序試試看。

1 -- 以下是先根據 U_Pwd 這一列進行分組,然後每一組再根據 U_Name 排序
2 select *,
3 '第'+convert(varchar,rank() over(partition by U_Pwd order by U_Name))+'名' RowNum
4 from UserInfo

 

1 -- 以下是先根據 U_Pwd 這一列進行分組,然後每一組再根據 U_Pwd 排序
2 select *,
3 '第'+convert(varchar,DENSE_RANK() over(partition by U_Pwd order by U_Pwd))+'名' RowNum
4 from UserInfo

因為 U_Pwd 這一列有4種不同的值,所以同樣是分為4組,然後 DENSE_RANK 再在每一組中進行排序,因為DENSE_RANK也是並列排序,所以全部都是第一名。下面換個欄位排序試試看。

1 -- 以下是先根據 U_Pwd 這一列進行分組,然後每一組再根據 U_Name 排序
2 select *,
3 '第'+convert(varchar,DENSE_RANK() over(partition by U_Pwd order by U_Name))+'名' RowNum
4 from UserInfo

 

1 -- 以下是先根據 U_Pwd 這一列進行分組,然後每一組再根據 NTILE(3) 指定的組數分組,最後在根據 order by 子句指定的欄位 U_Pwd 排序 
2 select *,
3 '第'+convert(varchar,NTILE(3) over(partition by U_Pwd order by U_Pwd))+'名' RowNum
4 from UserInfo

因為 U_Pwd 這一列有4種不同的值,所以同樣是分為4組。第1組有1條資料,所以就1個區。第2組有4條資料,4/3等於1餘數1,所以第2組分為3個區,又因餘數為1,所以第1個區附加1行。第3組有3條資料,3/3等於1餘數為0,所以第3組有3個區。第4組有2條資料,所以分為2個區。

PS:在排序開窗函式中使用 PARTITION BY 子句需要放置在 ORDER BY子句之前。