--> Title : MSSQL2005Ranking函數集
--> Author : wufeng4552
--> Date : 2009-11-03
一、row_number
row_number函数的用途是非常广泛,这个函数的功能是为查询出来的每一行记录生成一个序号。row_number函数的用法如下面的SQL语句所示
use Northwind
go
select row_number()over(order by TerritoryID)cnt,
TerritoryID,
RegionID
from Territories
/*
row_number TerritoryID RegionID
-------------------- -------------------- -----------
1 01581 1
2 01730 1
3 01833 1
4 02116 1
5 02139 1
6 02184 1
7 02903 1
8 03049 3
9 03801 3
*/
其中row_number列是由row_number函数生成的序号列。在使用row_number函数是要使用over子句选择对某一列进行排序,然后才能生成序号。
注意點:
row_number函数生成序号的基本原理是先使用over子句中的排序语句对记录进行排序,然后按着这个顺序生成序号。over子句中的order by子句与SQL语句中的order by子句没有任何关系,这两处的order by 可以完全不同,如下面的SQL语句所示
use Northwind
go
select row_number()over(order by (select 1))[row_number],
TerritoryID,
RegionID
from Territories order by newid()
/*
row_number TerritoryID RegionID
-------------------- -------------------- -----------
3 01833 1
52 98052 2
9 03801 3
41 80202 2
19 20852 1
27 40222 1
26 33607 4
50 95060 2
*/
如果不想按照某一字段排序可以這樣
use Northwind
go
select row_number()over(order by (select 1))[row_number],
TerritoryID,
RegionID
from Territories
--or
select row_number()over(order by getdate())[row_number],
TerritoryID,
RegionID
from Territories
如果先分組,然後再排序則可以用PARTITION BY 關鍵字
use Northwind
go
select row_number()over(partition by RegionID order by getdate() )[row_number],
TerritoryID,
RegionID
from Territories order by RegionID desc
/*
row_number TerritoryID RegionID
-------------------- -------------------- -----------
1 72716 4
2 75234 4
3 78759 4
4 29202 4
5 30346 4
6 31406 4
7 32859 4
8 33607 4
1 44122 3
2 45839 3
3 48075 3
4 48084 3
*/
我们可以使用row_number函数来实现查询表中指定范围的记录,一般将其应用到Web应用程序的分页功能上 如:
use Northwind
go
;with wufeng4552
as
(select row_number()over(order by getdate() )[row_number],
TerritoryID,
RegionID
from Territories
)
select * from wufeng4552 where [row_number] between 2 and 7
/*
row_number TerritoryID RegionID
-------------------- -------------------- -----------
2 01730 1
3 01833 1
4 02116 1
5 02139 1
6 02184 1
7 02903 1
(7 個資料列受到影響)
*/
二、rank
rank函数考虑到了over子句中排序字段值相同的情况,为了更容易说明问题 創建測試表
use Northwind
go
if object_id('tempdb..#')is not null drop table #
go
select top 6 * into # from Territories
--插入幾筆重複值
insert # select '01581','Westboro',1 union all
select '01730','Bedford',1 union all
select '01833','Georgetow',1
select TerritoryID,
TerritoryDescription
from # order by TerritoryID
/*
TerritoryID TerritoryDescription
-------------------- --------------------------------------------------
01581 Westboro
01581 Westboro
01730 Bedford
01730 Bedford
01833 Georgetow
01833 Georgetow
02116 Boston
02139 Cambridge
02184 Braintree
*/
use Northwind
go
if object_id('tempdb..#')is not null drop table #
go
select top 6 * into # from Territories
--插入幾筆重複值
insert # select '01581','Westboro',1 union all
select '01730','Bedford',1 union all
select '01833','Georgetow',1
select rank()over(order by TerritoryID)[row_number],
TerritoryID
from #
/*
row_number TerritoryID
-------------------- --------------------
1 01581
1 01581
3 01730
3 01730
5 01833
5 01833
7 02116
8 02139
9 02184
*/
從上面的結果來看TerritoryID相同的 序號相同01730 序號從3 開始而不是2
rank函数的使用方法与row_number函数完全相同
--2000的實現方法
select
[row_number]=isnull((select count(*) from # where TerritoryID<t.TerritoryID),0)+1,
TerritoryID
from # t order by TerritoryID
/*
row_number TerritoryID
----------- --------------------
1 01581
1 01581
3 01730
3 01730
5 01833
5 01833
7 02116
8 02139
9 02184
(9 個資料列受到影響)
*/
如果先分組,然後再排序則可以用PARTITION BY 關鍵字
select rank()over(partition by RegionID order by TerritoryID)[row_number],
TerritoryID
from #
三、dense_rank
dense_rank函数的功能与rank函数类似,只是在生成序号时是连续的,而rank函数生成的序号有可能不连续。如上面的例子中如果使用dense_rank函数
use Northwind
go
if object_id('tempdb..#')is not null drop table #
go
select top 6 * into # from Territories
--插入幾筆重複值
insert # select '01581','Westboro',1 union all
select '01730','Bedford',1 union all
select '01833','Georgetow',1
select dense_rank()over(order by TerritoryID)[row_number],
TerritoryID
from #
/*
row_number TerritoryID
-------------------- --------------------
1 01581
1 01581
2 01730
2 01730
3 01833
3 01833
4 02116
5 02139
6 02184
(9 個資料列受到影響)
*/
--2000的實現方法
select
[row_number]=isnull((select count(distinct TerritoryID) from # where TerritoryID<t.TerritoryID),0)+1,
TerritoryID
from # t order by TerritoryID
/*
row_number TerritoryID
----------- --------------------
1 01581
1 01581
2 01730
2 01730
3 01833
3 01833
4 02116
5 02139
6 02184
(9 個資料列受到影響)
*/
四、ntile
ntile函数可以对序号进行分组处理。这就相当于将查询出来的记录集放到指定长度的数组中,每一个数组元素存放一定数量的记录。ntile函数为每条记录生成的序号就是这条记录所有的数组元素的索引(从1开始)。也可以将每一个分配记录的数组元素称为“桶”。ntile函数有一个参数,用来指定桶数。下面的SQL语句使用ntile函数对表进行了装桶处理:
use Northwind
go
if object_id('tempdb..#')is not null drop table #
go
select top 6 * into # from Territories
--插入幾筆重複值
insert # select '01581','Westboro',1 union all
select '01730','Bedford',1 union all
select '01833','Georgetow',1
select TerritoryID,
TerritoryDescription,
ntile(4)over(order by getdate())[Groups]
from #
select TerritoryID,
TerritoryDescription,
ntile(4)over(partition by RegionID order by getdate())[Groups]
from #
/*
TerritoryID TerritoryDescription Groups
-------------------- -------------------------------------------------- --------------------
01581 Westboro 1
01730 Bedford 1
01833 Georgetow 1
01581 Westboro 2
01730 Bedford 2
01833 Georgetow 3
02116 Boston 3
02139 Cambridge 4
02184 Braintree 4
*/