分頁是應用開發核心需求。SQL Server 歷經多版本演進,提供多種分頁寫法。本文以「每頁 10 筆、查第 2 頁」為例,比較四種主流寫法,重點解析 SQL Server 2012+ 引入的標準 OFFSET/FETCH 語法優勢與用法細節。
資料表:dbo.Message,主鍵 Code,建立時間 CreateTime。需求:每頁 10 筆,取得第 2 頁(第 11-20 筆)。
SELECT TOP(20) * FROM dbo.Message WHERE Code NOT IN (SELECT TOP(10) Code FROM dbo.Message);
NOT IN 遇 NULL 值有陷阱,大資料量效能差。SELECT *, ROW_NUMBER() OVER(ORDER BY Code) AS rowNum INTO #a FROM dbo.Message; SELECT * FROM #a WHERE rowNum BETWEEN 11 AND 20; DROP TABLE #a;
WITH sss AS (
SELECT *, ROW_NUMBER() OVER(ORDER BY CreateTime) AS rowNum FROM DBO.Message
)
SELECT * FROM sss WHERE rowNum BETWEEN 11 AND 20;
SELECT * FROM DBO.Message ORDER BY CreateTime OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
屬於 ORDER BY 子句一部分,符合 ANSI SQL 標準,支援跳過功能,專為分頁設計。
ORDER BY <排序欄位>
OFFSET <跳過筆數> {ROW | ROWS}
[FETCH {FIRST | NEXT} <取得筆數> {ROW | ROWS} ONLY]
ROW/ROWS、FIRST/NEXT 可互換,提升可讀性(如 FETCH 1 ROW、OFFSET 0 ROWS)。OFFSET 跳過 N 筆並取得剩餘所有資料。PERCENT 與 WITH TIES 選項(TOP 支援)。-- 取得第 3 頁,每頁 25 筆,依訂單日期、ID 排序 SELECT orderid, orderdate, custid, empid FROM Sales.Orders ORDER BY orderdate, orderid OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY;
| 版本 | 推薦寫法 | 備註 |
|---|---|---|
| SQL 2000/2005/2008/R2 | CTE + ROW_NUMBER() | 相容性最好,效能穩定 |
| SQL 2012+ | OFFSET/FETCH | 標準語法、可讀性最佳、計畫重用率高 |
| 需 TOP PERCENT/WITH TIES | TOP | OFFSET/FETCH 不支援 |
結論:現代專案優先採用 OFFSET/FETCH,舊版維護專案使用 CTE 寫法。