CREATE PROCEDURE sp_page
@tb VARCHAR(50), -- 表名
@col VARCHAR(50), -- 排序欄位
@coltype INT, -- 欄位類型: 0=數值, 1=字串, 2=日期時間
@orderby BIT, -- 0=升序, 1=降序
@collist VARCHAR(800), -- 輸出欄位清單, * 表全部
@pagesize INT, -- 每頁筆數
@page INT, -- 目標頁碼 (1-based)
@condition VARCHAR(800), -- WHERE 條件 (不含 WHERE 關鍵字)
@pages INT OUTPUT -- 回傳總頁數
AS
BEGIN
DECLARE @sql NVARCHAR(4000), @where1 VARCHAR(800), @where2 VARCHAR(800);
-- 處理 WHERE 子句
IF @condition IS NULL OR RTRIM(@condition) = ''
BEGIN
SET @where1 = ' WHERE ';
SET @where2 = '';
END
ELSE
BEGIN
SET @where1 = ' WHERE (' + @condition + ') AND ';
SET @where2 = ' WHERE (' + @condition + ') ';
END
-- 計算總頁數
SET @sql = N'SELECT @pages = CEILING((COUNT(*) + 0.0) / ' + CAST(@pagesize AS VARCHAR) + N') FROM ' + @tb + @where2;
EXEC sp_executesql @sql, N'@pages INT OUTPUT', @pages OUTPUT;
-- 第 1 頁特殊處理 (無需子查詢)
IF @page = 1
BEGIN
SET @sql = N'SELECT TOP ' + CAST(@pagesize AS VARCHAR) + N' ' + @collist +
N' FROM ' + @tb + @where2 + N' ORDER BY ' + @col +
CASE @orderby WHEN 0 THEN '' ELSE ' DESC' END;
EXEC(@sql);
RETURN;
END
-- 一般頁數:利用子查詢取得上一頁邊界值
IF @orderby = 0 -- 升序
BEGIN
SET @sql = N'SELECT TOP ' + CAST(@pagesize AS VARCHAR) + N' ' + @collist +
N' FROM ' + @tb + @where1 + @col + N' > (' +
N'SELECT MAX(' + @col + N') FROM (' +
N'SELECT TOP ' + CAST(@pagesize * (@page - 1) AS VARCHAR) + N' ' + @col +
N' FROM ' + @tb + @where2 + N' ORDER BY ' + @col + N') t) ' +
N'ORDER BY ' + @col;
END
ELSE -- 降序
BEGIN
SET @sql = N'SELECT TOP ' + CAST(@pagesize AS VARCHAR) + N' ' + @collist +
N' FROM ' + @tb + @where1 + @col + N' < (' +
N'SELECT MIN(' + @col + N') FROM (' +
N'SELECT TOP ' + CAST(@pagesize * (@page - 1) AS VARCHAR) + N' ' + @col +
N' FROM ' + @tb + @where2 + N' ORDER BY ' + @col + N' DESC) t) ' +
N'ORDER BY ' + @col + N' DESC';
END
EXEC(@sql);
END;
GO
DECLARE @totalPages INT;
EXEC sp_page
@tb = 'Orders',
@col = 'OrderDate',
@coltype = 2,
@orderby = 1, -- 依日期降序
@collist = 'OrderID, CustomerID, OrderDate, TotalAmount',
@pagesize = 20,
@page = 3,
@condition = 'CustomerID = ''ALFKI'' AND OrderDate >= ''2023-01-01''',
@pages = @totalPages OUTPUT;
SELECT @totalPages AS TotalPages;
此存儲程序展示 SQL Server 2000 時代高效分頁的經典模式:動態 SQL、邊界值法、參數化總頁數計算。雖現代版本已有 `OFFSET/FETCH` 與 `ROW_NUMBER()`,但理解其原理有助於維護舊系統與領會分頁演算法本質。