預存程式完整代碼
CREATE PROCEDURE sp_page
@tb VARCHAR(20), -- 表名
@col VARCHAR(20), -- 分頁依據欄位
@coltype BIT, -- 欄位類型: 0=數值, 1=字串
@collist VARCHAR(800), -- 查詢欄位清單
@selecttype INT, -- 查詢類型: 1=上頁,2=下頁,3=首頁,4=末頁,5=指定頁
@pagesize INT, -- 每頁筆數
@page INT, -- 指定頁碼
@minid VARCHAR(50), -- 當前頁最小值
@maxid VARCHAR(50) -- 當前頁最大值
AS
DECLARE @sql VARCHAR(8000)
-- 字串型值加單引號
IF @coltype = 1 BEGIN
SET @minid = '''' + @minid + ''''
SET @maxid = '''' + @maxid + ''''
END
-- 動態 SQL 依類型生成
SET @sql = CASE @selecttype
WHEN 1 THEN -- 上一頁
'SELECT ' + @collist + ' FROM (SELECT TOP ' + CAST(@pagesize AS VARCHAR) +
' ' + @collist + ' FROM ' + @tb + ' WHERE ' + @col + ' < ' + @minid +
' ORDER BY ' + @col + ' DESC) t ORDER BY ' + @col
WHEN 2 THEN -- 下一頁
'SELECT TOP ' + CAST(@pagesize AS VARCHAR) + ' ' + @collist +
' FROM ' + @tb + ' WHERE ' + @col + ' > ' + @maxid + ' ORDER BY ' + @col
WHEN 3 THEN -- 首頁
'SELECT TOP ' + CAST(@pagesize AS VARCHAR) + ' ' + @collist +
' FROM ' + @tb + ' ORDER BY ' + @col
WHEN 4 THEN -- 末頁
'SELECT ' + @collist + ' FROM (SELECT TOP ' + CAST(@pagesize AS VARCHAR) +
' ' + @collist + ' FROM ' + @tb + ' ORDER BY ' + @col + ' DESC) t ORDER BY ' + @col
WHEN 5 THEN -- 指定頁
'SELECT TOP ' + CAST(@pagesize AS VARCHAR) + ' ' + @collist +
' FROM ' + @tb + ' WHERE ' + @col + ' NOT IN ' +
'(SELECT TOP ' + CAST(@pagesize * (@page - 1) AS VARCHAR) + ' ' + @col +
' FROM ' + @tb + ' ORDER BY ' + @col + ') ORDER BY ' + @col
END
EXEC(@sql)
GO
設計特點與適用場景
- 雙向游標導航:透過 @minid/@maxid 實作上/下頁,避免 OFFSET 掃描。
- 支援字串/數值欄位:@coltype 自動處理引號。
- 指定頁跳轉:使用 NOT IN 子查詢跳過前 N 頁(注意:大頁碼效能遞減)。
- 動態 SQL 靈活:表名、欄位、條件皆可參數化。
效能考量與改進建議
- 指定頁模式 (type=5) 在大頁碼時效能差:NOT IN 子查詢需掃描前 N×pagesize 筆。建議改用
WHERE col > (SELECT MAX(col) FROM (SELECT TOP N col FROM ...) 或 Keyset Pagination。
- 缺乏總筆數統計:前端需另行查詢
COUNT(*) 顯示總頁數。
- 動態 SQL 注入風險:生產環境務必驗證/過濾 @tb、@col 等參數,或改用參數化查詢。
- 適用於有序唯一鍵分頁:@col 應為主鍵或唯一索引欄位,否則邊界條件可能遺漏/重複資料。
現代替代方案: MySQL 8.0+ / PostgreSQL / SQL Server 2012+ 內建 OFFSET ... FETCH NEXT 或 LIMIT ... OFFSET,配合索引覆蓋查詢通常已足夠;超大資料集建議採用 Keyset Pagination (Seek Method):WHERE id > last_seen_id ORDER BY id LIMIT N。