SELECT * FROM (SELECT bh,title,time,row_number() OVER(ORDER BY bh) AS row FROM shang_cms_news WHERE smallclass=6 ) C WHERE (row between 5 and 7 )
1. row_number
2. rank html
3. dense_rank java
4. ntile
下面分别介绍一下这四个排名函数的功能及用法。在介绍以前假设有一个t_table表,表结构与表中的数据如图1所示: 算法
图1
其中field1字段的类型是int,field2字段的类型是varchar 数组
1、row_number 函数
row_number函数的用途是很是普遍,这个函数的功能是为查询出来的每一行记录生成一个序号。row_number函数的用法以下面的SQL语句所示: spa
select
row_number()
over
(
order
by
field1)
as
row_number,
*
from
t_table
上面的SQL语句的查询结果如图2所示。 .net
图2
其中row_number列是由row_number函数生成的序号列。在使用row_number函数是要使用over子句选择对某一列进行排序,而后才能生成序号。 htm
实际上,row_number函数生成序号的基本原理是先使用over子句中的排序语句对记录进行排序,而后按着这个顺序生成序号。over子句中的order by子句与SQL语句中的order by子句没有任何关系,这两处的order by 能够彻底不一样,以下面的SQL语句所示: blog
select
row_number()
over
(
order
by
field2
desc
)
as
row_number,
*
from
t_table
order
by
field1
desc
上面的SQL语句的查询结果如图3所示。 排序
图3
咱们可使用row_number函数来实现查询表中指定范围的记录,通常将其应用到Web应用程序的分页功能上。下面的SQL语句能够查询t_table表中第2条和第3条记录:
with
t_rowtable
as
(
select
row_number()
over
(
order
by
field1)
as
row_number,
*
from
t_table
)
select
*
from
t_rowtable
where
row_number
>
1
and
row_number
<
4
order
by
field1
上面的SQL语句的查询结果如图4所示。
图4
上面的SQL
语句使用了CTE
,关于CTE
的介绍将读者参阅
《SQL Server2005杂谈(1):使用公用表表达式(CTE)简化嵌套SQL》
。
另外要注意的是,若是将row_number
函数用于分页处理,over
子句中的order by
与排序记录的order by
应相同,不然生成的序号可能不是有续的。
固然,不使用row_number
函数也能够实现查询指定范围的记录,就是比较麻烦。通常的方法是使用颠倒Top
来实现,例如,查询t_table
表中第2
条和第3
条记录,能够先查出前3
条记录,而后将查询出来的这三条记录按倒序排序,再取前2
条记录,最后再将查出来的这2
条记录再按倒序排序,就是最终结果。SQL
语句以下:
select
*
from
(
select
top
2
*
from
(
select
top
3
*
from
t_table
order
by
field1) a
order
by
field1
desc
) b
order
by
field1
上面的SQL语句查询出来的结果如图5所示。
图5
这个查询结果除了没有序号列row_number,其余的与图4所示的查询结果彻底同样。
2、rank
rank函数考虑到了over子句中排序字段值相同的状况,为了更容易说明问题,在t_table表中再加一条记录,如图6所示。
图6
在图6所示的记录中后三条记录的field1字段值是相同的。若是使用rank函数来生成序号,这3条记录的序号是相同的,而第4条记录会根据当前的记录 数生成序号,后面的记录依此类推,也就是说,在这个例子中,第4条记录的序号是4,而不是2。rank函数的使用方法与row_number函数彻底相 同,SQL语句以下:
select
rank()
over
(
order
by
field1),
*
from
t_table
order
by
field1
上面的SQL语句的查询结果如图7所示。
图7
3、dense_rank
dense_rank函数的功能与rank函数相似,只是在生成序号时是连续的,而rank函数生成的序号有可能不连续。如上面的例子中若是使用dense_rank函数,第4条记录的序号应该是2,而不是4。以下面的SQL语句所示:
select
dense_rank()
over
(
order
by
field1),
*
from
t_table
order
by
field1
上面的SQL语句的查询结果如图8所示。
图8
读者能够比较图7和图8所示的查询结果有什么不一样
4、ntile
ntile函数能够对序号进行分组处理。这就至关于将查询出来的记录集放到指定长度的数组中,每个数组元素存放必定数量的记录。ntile函数为每条记 录生成的序号就是这条记录全部的数组元素的索引(从1开始)。也能够将每个分配记录的数组元素称为“桶”。ntile函数有一个参数,用来指定桶数。下 面的SQL语句使用ntile函数对t_table表进行了装桶处理:
select
ntile(
4
)
over
(
order
by
field1)
as
bucket,
*
from
t_table
上面的SQL语句的查询结果如图9所示。
图9
因为t_table表的记录总数是6,而上面的SQL语句中的ntile函数指定了桶数为4。
也许有的读者会问这么一个问题,SQL Server2005怎么来决定某一桶应该放多少记录呢?可能t_table表中的记录数有些少,那么咱们假设t_table表中有59条记录,而桶数是5,那么每一桶应放多少记录呢?
实际上经过两个约定就能够产生一个算法来决定哪个桶应放多少记录,这两个约定以下:
1. 编号小的桶放的记录不能小于编号大的桶。也就是说,第1捅中的记录数只能大于等于第2桶及之后的各桶中的记录。
2. 全部桶中的记录要么都相同,要么从某一个记录较少的桶开始后面全部捅的记录数都与该桶的记录数相同。也就是说,若是有个桶,前三桶的记录数都是10,而第4捅的记录数是6,那么第5桶和第6桶的记录数也必须是6。
根据上面的两个约定,能够得出以下的算法:
//
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
}
根据上面的算法,若是记录总数为59,桶数为5,则前4个桶的记录数都是12,最后一个桶的记录数是11。
若是记录总数为53,桶数为5,则前3个桶的记录数为11,后2个桶的记录数为10。
就拿本例来讲,记录总数为6
,桶数为4
,则会算出recordCount1
的值为2
,在结束while
循环后,会算出recordCount2
的值是1
,所以,前2
个桶的记录是2
,后2
个桶的记录是1
。