開發論壇或列表頁面時,若一次性查出全表數據不僅浪費資源,更嚴重拖慢回應速度。本文提供一個經實戰驗證的分頁存儲過程 Sp_Conn_Sort,支援總筆數統計、條件篩選、動態排序與高效分頁查詢,並附贈 ASP.NET 後端調用與前端翻頁 UI 完整實作。
過程接受 7 個參數,涵蓋表名、查詢欄位、排序欄位、頁大小、頁碼、是否統計總數、排序方向與 WHERE 條件:
CREATE PROCEDURE Sp_Conn_Sort (
@tblName VARCHAR(255), -- 表名
@strGetFields VARCHAR(1000) = '*',-- 返回欄位
@fldName VARCHAR(255) = '', -- 排序欄位
@PageSize INT = 40, -- 頁大小
@PageIndex INT = 1, -- 頁碼
@doCount BIT = 0, -- 非 0 時回傳總筆數
@OrderType BIT = 0, -- 非 0 時降序
@strWhere VARCHAR(1500) = '' -- WHERE 條件(勿加 WHERE 關鍵字)
) AS
BEGIN
DECLARE @strSQL VARCHAR(5000), @strTmp VARCHAR(110), @strOrder VARCHAR(400);
-- 統計總筆數
IF @doCount != 0 BEGIN
SET @strSQL = @strWhere != ''
? 'SELECT COUNT(*) AS Total FROM ' + @tblName + ' WHERE ' + @strWhere
: 'SELECT COUNT(*) AS Total FROM ' + @tblName;
END
ELSE BEGIN
-- 動態構建排序片段
IF @OrderType != 0 BEGIN
SET @strTmp = '<(SELECT MIN';
SET @strOrder = ' ORDER BY ' + @fldName + ' DESC';
END ELSE BEGIN
SET @strTmp = '>(SELECT MAX';
SET @strOrder = ' ORDER BY ' + @fldName + ' ASC';
END
-- 第一頁直接 TOP N,後續頁用「排序欄位 >/< 子查詢」避免掃描大量前置行
IF @PageIndex = 1 BEGIN
SET @strSQL = @strWhere != ''
? 'SELECT TOP ' + STR(@PageSize) + ' ' + @strGetFields + ' FROM ' + @tblName + ' WHERE ' + @strWhere + ' ' + @strOrder
: 'SELECT TOP ' + STR(@PageSize) + ' ' + @strGetFields + ' FROM ' + @tblName + ' ' + @strOrder;
END ELSE BEGIN
SET @strSQL = 'SELECT TOP ' + STR(@PageSize) + ' ' + @strGetFields + ' FROM ' + @tblName + ' WHERE ' + @fldName + ' ' + @strTmp + '(' + @fldName + ') FROM (SELECT TOP ' + STR((@PageIndex-1)*@PageSize) + ' ' + @fldName + ' FROM ' + @tblName + ' ' + @strOrder + ') AS tblTmp) ' + @strOrder;
IF @strWhere != ''
SET @strSQL = 'SELECT TOP ' + STR(@PageSize) + ' ' + @strGetFields + ' FROM ' + @tblName + ' WHERE ' + @fldName + ' ' + @strTmp + '(' + @fldName + ') FROM (SELECT TOP ' + STR((@PageIndex-1)*@PageSize) + ' ' + @fldName + ' FROM ' + @tblName + ' WHERE ' + @strWhere + ' ' + @strOrder + ') AS tblTmp) AND ' + @strWhere + ' ' + @strOrder;
END
END
EXEC (@strSQL);
END
ASP.NET 代碼後置示範兩次呼叫存儲過程:第一次 @doCount=1 取總筆數,第二次取分頁數據;BuildPages() 動態產生「上一頁、頁碼、下一頁、尾頁」連結,支援當前頁附近顯示固定寬度頁碼區塊:
private void BuidGrid() {
using (var con = new SqlConnection(ConfigurationManager.AppSettings["constr"])) {
con.Open();
// 1. 取總筆數
using (var cmd = new SqlCommand("Sp_Conn_Sort", con) { CommandType = CommandType.StoredProcedure }) {
cmd.Parameters.Add(new SqlParameter("@doCount", 1));
cmd.Parameters.Add(new SqlParameter("@tblName", "num_s"));
ToatalCountRecord = Convert.ToInt32(cmd.ExecuteScalar());
}
// 2. 取分頁數據
using (var sda = new SqlDataAdapter("Sp_Conn_Sort", con)) {
sda.SelectCommand.CommandType = CommandType.StoredProcedure;
sda.SelectCommand.Parameters.AddRange(new[] {
new SqlParameter("@tblName", "num_s"),
new SqlParameter("@PageSize", PageItem),
new SqlParameter("@PageIndex", CurrentPage),
new SqlParameter("@fldName", "id")
});
var ds = new DataSet();
sda.Fill(ds);
GridView1.DataSource = ds;
GridView1.DataBind();
}
}
BuildPages();
}
<div>
<div id="PageInfo" runat="server"></div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="id">
<Columns>
<asp:BoundField DataField="id" HeaderText="編號" />
<asp:BoundField DataField="num" HeaderText="號碼" />
</Columns>
</asp:GridView>
</div>
此方案適合中小型專案快速落地,存儲過程邏輯清晰,前端翻頁控制靈活,可直接套用於實際專案並依需求微調。