CREATE PROCEDURE dbo.usp_SplitPage
@sql NVARCHAR(4000), -- 查詢語句(不含 ORDER BY)
@page INT = 1, -- 頁碼(1-based)
@pageSize INT, -- 每頁筆數
@pageCount INT = 0 OUTPUT, -- 總頁數
@recordCount INT = 0 OUTPUT -- 總筆數
AS
BEGIN
SET NOCOUNT ON;
DECLARE @cursor INT;
-- 開啟唯讀、順向游標
EXEC sp_cursoropen @cursor OUTPUT, @sql, @scrollopt = 1, @ccopt = 1, @rowcount = @pageCount OUTPUT;
SET @recordCount = @pageCount;
-- 計算總頁數、起始位置
SET @pageCount = CEILING(1.0 * @pageCount / @pageSize);
SET @page = (@page - 1) * @pageSize + 1; -- 游標為 1-based
-- 擷取指定頁資料
EXEC sp_cursorfetch @cursor, 16, @page, @pageSize; -- 16 = FETCH_NEXT + 傳回資料
-- 關閉游標
EXEC sp_cursorclose @cursor;
END;
GO
<%
Dim sql, page, pageSize, pageCount, recordCount, cmd, rs
sql = "SELECT ID, Title FROM News WHERE Deleted = 0 ORDER BY ID DESC"
page = CInt(Request.QueryString("page"))
If page <= 0 Then page = 1
pageSize = 20
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandType = 4 ' adCmdStoredProc
cmd.CommandText = "usp_SplitPage"
cmd.Parameters.Append cmd.CreateParameter("@sql", 202, 1, 4000, sql) ' adVarWChar, adParamInput
cmd.Parameters.Append cmd.CreateParameter("@page", 3, 1, , page) ' adInteger
cmd.Parameters.Append cmd.CreateParameter("@pageSize", 3, 1, , pageSize)
cmd.Parameters.Append cmd.CreateParameter("@pageCount", 3, 2, , pageCount) ' adParamOutput
cmd.Parameters.Append cmd.CreateParameter("@recordCount", 3, 2, , recordCount)
Set rs = cmd.Execute
%>
<table>
<% Do Until rs.EOF %>
<tr><td><%= rs("ID") %></td><td><%= rs("Title") %></td></tr>
<% rs.MoveNext : Loop %>
</table>
<%
' 輸出分頁導覽
Response.Write "總筆數: " & recordCount & " | 總頁數: " & pageCount & " | 目前頁: " & page
rs.Close : Set rs = Nothing : Set cmd = Nothing
%>
| 項目 | 說明 |
|---|---|
| 參數化查詢 | 使用 Command.Parameters 防止 SQL 注入,利於計畫重用。 |
| 游標選項 | @scrollopt=1 (KEYSET), @ccopt=1 (READ_ONLY),低鎖定、低記憶體。 |
| NOCOUNT ON | 減少 DONE_IN_PROC 網路封包。 |
| 索引支援 | ORDER BY 欄位需有索引,避免 Sort 運算子。 |
CREATE PROCEDURE usp_SplitPage_Modern
@PageNumber INT = 1,
@PageSize INT = 20,
@TotalRows INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT @TotalRows = COUNT(*) FROM dbo.News WHERE Deleted = 0;
SELECT ID, Title
FROM dbo.News
WHERE Deleted = 0
ORDER BY ID DESC
OFFSET (@PageNumber - 1) * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
END;
OFFSET ... FETCH 為 ANSI SQL 標準,效能優於游標,語法簡潔。舊版 ASP 專案若無法升級資料庫,游標分頁仍是可行方案;新專務必使用 OFFSET/FETCH,並搭配參數化命令物件,確保安全與效能。