SQL Server 2000 分頁常用「建立含 Identity 的暫存表 → 插入排序結果 → 依 Identity 篩選頁碼」,效能差、程式碼繁。SQL 2005 引入 ROW_NUMBER()、RANK()、DENSE_RANK()、NTILE() 等視窗函數,單一查詢即可完成高效分頁。
CREATE PROC northwind_OrdersPaged @PageIndex INT, @PageSize INT
AS
SET ROWCOUNT @PageSize * (@PageIndex + 1);
CREATE TABLE #PageIndex (IndexId INT IDENTITY(1,1), OrderID INT);
INSERT #PageIndex (OrderID) SELECT OrderID FROM Orders ORDER BY OrderID DESC;
SELECT COUNT(OrderID) FROM Orders;
SELECT O.* FROM Orders O, #PageIndex P
WHERE O.OrderID = P.OrderID AND P.IndexId > @PageSize*@PageIndex AND P.IndexId <= @PageSize*(@PageIndex+1)
ORDER BY P.IndexId;
缺點:SET ROWCOUNT 影響後續陳述式、暫存表寫入/讀取 IO、IDENTITY 間隙導致頁碼偏移。
CREATE PROC Orders_Paged_2005
@PageIndex INT = 0, -- 0-based
@PageSize INT = 20
AS
BEGIN
SET NOCOUNT ON;
;WITH Numbered AS (
SELECT
ROW_NUMBER() OVER (ORDER BY OrderID DESC) AS RowNum,
OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, ShippedDate,
ShipVia, Freight, ShipName, ShipAddress, ShipCity, ShipRegion,
ShipPostalCode, ShipCountry
FROM dbo.Orders
)
SELECT *
FROM Numbered
WHERE RowNum BETWEEN @PageIndex * @PageSize + 1 AND (@PageIndex + 1) * @PageSize
ORDER BY RowNum;
-- 總筆數 (可分開查詢或加 COUNT() OVER)
SELECT COUNT(*) FROM dbo.Orders;
END;
GO
SELECT OrderID, CustomerID, OrderDate
FROM dbo.Orders
ORDER BY OrderID DESC
OFFSET @PageIndex * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
COUNT(*) OVER() 可單查詢回傳總筆數與分頁資料| 函數 | 行為 | 典型用途 |
|---|---|---|
ROW_NUMBER() | 連續不重複 1,2,3... | **分頁、去重取第一筆** |
RANK() | 相同值同序,下一序跳號 (1,2,2,4) | 排名榜、並列名次 |
DENSE_RANK() | 相同值同序,下一序不跳 (1,2,2,3) | 密集排名、分組排序 |
NTILE(n) | 分成 n 桶,均勻分配 | 四分位數、百分位、分桶分析 |