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
。