Sql Server2005對t-sql的增強之排名函數 (轉)

Sql Server2005中新增加了4個排名函數:ROW_NUMBER, RANK, DENSE_RANK, NTILE;大家一定已經對ROW_NUMBER非常熟悉了,所以我從最後一個NTILE開始分析。

NTILEmsdn中的解釋是:將有序分區中的行分發到指定數目的組中。各個組有編號,編號從一開始。對於每一個行,NTILE 將返回此行所屬的組的編號。不知道大家是不是一下子就能看懂這個解釋,反正我是結合解釋自己寫了例子才弄明白的。

準備腳本,我們創建一個簡單的3列表,三列分別是idcategoryId,和name,如下:

GO
if object_id('t_ntile','U'is not null
drop table t_ntile;
GO
create table t_ntile
(
    id 
int unique not null,
    categoryId 
int not null,
    name 
nvarchar(20)
)
go
INSERT INTO t_ntile VALUES(1,1,'A')
INSERT INTO t_ntile VALUES(2,4,'B')
INSERT INTO t_ntile VALUES(3,2,'C')
INSERT INTO t_ntile VALUES(4,1,'D')
INSERT INTO t_ntile VALUES(5,3,'E')
INSERT INTO t_ntile VALUES(6,3,'F')
INSERT INTO t_ntile VALUES(7,2,'G')
INSERT INTO t_ntile VALUES(8,2,'H')
INSERT INTO t_ntile VALUES(9,2,'I')
Go

 

查詢語句如下:


SELECT id,categoryId,name
    ,
'ntile value' = NTILE(3OVER(PARTITION BY categoryId ORDER BY categoryId) 
FROM t_ntile

我們給NTITL傳的參數是3,即表示三行作爲一組,然後OVER中表達式指定要根據categoryId來分割分組,並要按照categoryId排序。上面的表達式執行結果如下:

----------------------------分割線-------------------------------

下面看RANKDENSE_RANK這對兄弟函數,這對函數要比NTITL容易理解一些。MSDNRANK的解釋:返回結果集的分區內每行的排名。行的排名是相關行之前的排名數加一。MSDN上對DENSE_RANK的解釋是:返回結果集分區中行的排名,在排名中沒有任何間斷。行的排名等於所討論行之前的所有排名數加一。下面我用一個例子來說明一下,用結果說明他們的差別:

if object_id('student_class_grade','U'is not null
drop table student_class_grade;
GO
create table student_class_grade
(
    student_id 
int--學生id
    class_no int--班級編號
    grade int --成績
);
GO
INSERT INTO student_class_grade VALUES(1,1,90);
INSERT INTO student_class_grade VALUES(2,1,85);
INSERT INTO student_class_grade VALUES(3,1,80);
INSERT INTO student_class_grade VALUES(4,1,80);
INSERT INTO student_class_grade VALUES(5,1,90);
INSERT INTO student_class_grade VALUES(6,1,75);
INSERT INTO student_class_grade VALUES(7,1,89);

INSERT INTO student_class_grade VALUES(11,2,90);
INSERT INTO student_class_grade VALUES(12,2,85);
INSERT INTO student_class_grade VALUES(13,2,80);
INSERT INTO student_class_grade VALUES(14,2,80);
INSERT INTO student_class_grade VALUES(15,2,90);
INSERT INTO student_class_grade VALUES(16,2,75);
INSERT INTO student_class_grade VALUES(17,2,89);
GO
--顯示各個班級學生的成績排名
SELECT student_id
    ,class_no,grade
    ,
'名次' = RANK() OVER(PARTITION BY class_no ORDER BY grade desc)
FROM student_class_grade
GO
SELECT student_id
    ,class_no,grade
    ,
'名次' = DENSE_RANK() OVER(PARTITION BY class_no ORDER BY grade desc)
FROM student_class_grade

分別執行下面兩個select腳本,可以得到如下的結果

可以看到1班同學的排名依次是1,1,3,4有了並列第一之後第二名的排序就是3了。

如下是DENSE_RANK的執行結果:

可以看到排名依次是1,1,2,3 … 當出現兩個並列第一之後,第二名的排名是2,而非RANK中的3.所以我們在給學生成績排名時可以用DENSE_RANK而不是RANK

---------------------------分割線-------------------

最後要介紹的是ROW_NUMBER這個函數爲我們分頁提供了便利。我們可以結合CTE(通用表表達式)使用,如下例子

WITH CTE_rn (student_id,class_no,grade,rn) AS(
    
SELECT student_id,class_no,grade,rn = ROW_NUMBER() OVER(ORDER BY student_id ASC)
    
FROM student_class_grade
    
WHERE 0=0 --可以在此處加一些過濾條件,這樣下面的分頁的sql中就都不需要加條件了
)
--獲得第-10條的數據
SELECT student_id,class_no,grade FROM CTE_rn WHERE rn BETWEEN 6 AND 10;
SELECT totalCn = COUNT(*FROM student_class_grade WHERE 0=0

 

來自 http://www.cnblogs.com/yukaizhao/archive/2008/04/28/sql_server_feature_rank_function.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章