Sql Server2005中新增加了4个排名函数:ROW_NUMBER, RANK, DENSE_RANK, NTILE;大家一定已经对ROW_NUMBER非常熟悉了,所以我从最后一个NTILE开始分析。(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
NTILEmsdn中的解释是:将有序分区中的行分发到指定数目的组中。各个组有编号,编号从一开始。对于每一个行,NTILE 将返回此行所属的组的编号。不知道大家是不是一下子就能看懂这个解释,反正我是结合解释自己写了例子才弄明白的。 准备脚本,我们创建一个简单的3列表,三列分别是idcategoryId,和name,如下:(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
GO(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
if object_id('t_ntile','U') is not null(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
drop table t_ntile;(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
GO(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
create table t_ntile(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
((ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    id
int unique not null,(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    categoryId
int not null,(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    name
nvarchar(20)(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
)(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
go(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO t_ntile VALUES(1,1,'A')(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO t_ntile VALUES(2,4,'B')(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO t_ntile VALUES(3,2,'C')(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO t_ntile VALUES(4,1,'D')(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO t_ntile VALUES(5,3,'E')(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO t_ntile VALUES(6,3,'F')(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO t_ntile VALUES(7,2,'G')(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO t_ntile VALUES(8,2,'H')(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO t_ntile VALUES(9,2,'I')(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
Go(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
查询语句如下:(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
SELECT id,categoryId,name(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    ,
'ntile value' = NTILE(3) OVER(PARTITION BY categoryId ORDER BY categoryId) FROM t_ntile
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
我们给
NTITL传的参数是3,即表示三行作为一组,然后OVER中表达式指定要根据categoryId来分割分组,并要按照categoryId排序。上面的表达式执行结果如下:(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
----------------------------分割线-------------------------------(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
下面看RANKDENSE_RANK这对兄弟函数,这对函数要比NTITL容易理解一些。MSDNRANK的解释:返回结果集的分区内每行的排名。行的排名是相关行之前的排名数加一。MSDN上对DENSE_RANK的解释是:返回结果集分区中行的排名,在排名中没有任何间断。行的排名等于所讨论行之前的所有排名数加一。下面我用一个例子来说明一下,用结果说明他们的差别:(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
if object_id('student_class_grade','U') is not null(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
drop table student_class_grade;(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
GO(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
create table student_class_grade(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
((ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    student_id
int, --学生id(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    class_no int, --班级编号(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    grade int --成绩(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
GO(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(1,1,90);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(2,1,85);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(3,1,80);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(4,1,80);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(5,1,90);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(6,1,75);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(7,1,89);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(11,2,90);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(12,2,85);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(13,2,80);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(14,2,80);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(15,2,90);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(16,2,75);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
INSERT INTO student_class_grade VALUES(17,2,89);(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
GO(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
--显示各个班级学生的成绩排名(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
SELECT student_id(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    ,class_no,grade(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    ,
'名次' = RANK() OVER(PARTITION BY class_no ORDER BY grade desc)(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
FROM student_class_grade(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
GO(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
SELECT student_id(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    ,class_no,grade(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
    ,
'名次' = DENSE_RANK() OVER(PARTITION BY class_no ORDER BY grade desc)(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
FROM student_class_grade(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
分别执行下面两个
select脚本,可以得到如下的结果(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
可以看到1班同学的排名依次是1,1,3,4有了并列第一之后第二名的排序就是3了。(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
如下是DENSE_RANK的执行结果:(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
可以看到排名依次是1,1,2,3 … 当出现两个并列第一之后,第二名的排名是2,而非RANK中的3.所以我们在给学生成绩排名时可以用DENSE_RANK而不是RANK(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
---------------------------分割线-------------------(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
最后要介绍的是ROW_NUMBER这个函数为我们分页提供了便利。我们可以结合CTE(通用表表达式)使用,如下例子(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
WITH CTE_rn (student_id,class_no,grade,rn) AS((ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
   
SELECT student_id,class_no,grade,rn = ROW_NUMBER() OVER(ORDER BY student_id ASC)(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
   
FROM student_class_grade(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
   
WHERE 0=0 --可以在此处加一些过滤条件,这样下面的分页的sql中就都不需要加条件了(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
)(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
--获得第-10条的数据(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
SELECT student_id,class_no,grade FROM CTE_rn WHERE rn BETWEEN 6 AND 10;(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
SELECT totalCn = COUNT(*) FROM student_class_grade WHERE 0=0(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð
全文结束。
(ëD\JéÛ·www.netcsharp.cn¤yH6ÅBÞëþð