存儲過程完整代碼
CREATE PROCEDURE [dbo].[proc_Page_BaseInfo]
@TableName NVARCHAR(4000), -- 表名(建議含架構 dbo.Table)
@PkField NVARCHAR(100), -- 排序/分頁鍵(唯一列)
@PageIndex INT = 1, -- 1-based 頁碼
@PageSize INT = 10, -- 頁大小
@SqlWhere NVARCHAR(4000) = '1=1', -- WHERE 條件(不含 WHERE)
@RowCount BIGINT OUTPUT, -- 總行數
@PageCount BIGINT OUTPUT -- 總頁數
AS
BEGIN
SET NOCOUNT ON;
-- 參數修正
IF @PageSize <= 0 SET @PageSize = 10;
IF @PageIndex <= 0 SET @PageIndex = 1;
IF @SqlWhere = '1' SET @SqlWhere = '1=1';
DECLARE @StartRow BIGINT = (@PageIndex - 1) * @PageSize + 1;
DECLARE @EndRow BIGINT = @StartRow + @PageSize - 1;
DECLARE @Sql NVARCHAR(MAX);
-- 分頁查詢(ROW_NUMBER 模式,SQL 2005+)
SET @Sql = N'
SELECT * FROM (
SELECT ROW_NUMBER() OVER (ORDER BY ' + QUOTENAME(@PkField) + N' DESC) AS RowId, *
FROM ' + @TableName + N'
WHERE ' + @SqlWhere + N'
) t
WHERE RowId BETWEEN ' + CAST(@StartRow AS NVARCHAR(20)) + N' AND ' + CAST(@EndRow AS NVARCHAR(20));
EXEC sp_executesql @Sql;
-- 統計總行數
SET @Sql = N'SELECT @RowCount = COUNT(*) FROM ' + @TableName + N' WHERE ' + @SqlWhere;
EXEC sp_executesql @Sql, N'@RowCount BIGINT OUTPUT', @RowCount OUTPUT;
-- 計算總頁數
SET @PageCount = CASE WHEN @RowCount % @PageSize = 0
THEN @RowCount / @PageSize
ELSE @RowCount / @PageSize + 1 END;
END;
調用示例
DECLARE @Rows BIGINT, @Pages BIGINT;
EXEC proc_Page_BaseInfo
@TableName = 'dbo.Orders',
@PkField = 'OrderID',
@PageIndex = 3,
@PageSize = 20,
@SqlWhere = 'OrderDate >= ''2024-01-01'' AND Status = 1',
@RowCount = @Rows OUTPUT,
@PageCount = @Pages OUTPUT;
SELECT @Rows AS TotalRows, @Pages AS TotalPages;
設計要點與改進建議
| 方面 | 當前實現 | 改進方向 |
| SQL 注入風險 | 動態拼接表名/列名/WHERE | 白名單驗證表名/列名;WHERE 條件改用參數化或 TVP 傳遞 |
| 性能:深分頁 | ROW_NUMBER 全排序後過濾 | 大表深分頁改用 Keyset Pagination(WHERE Pk > @LastPk ORDER BY Pk LIMIT N) |
| 排序靈活性 | 單列 DESC 固定 | 增加 @OrderBy 參數,支持多列、ASC/DESC |
| 統計一致性 | 查詢與統計分兩次執行 | 並發高時可能不一致,可用快照隔離或合併 CTE |
| 計劃緩存 | 動態 SQL 每次不同文本 | 參數化 WHERE 值、固定表名/列名模式,利用計劃復用 |
現代替代:OFFSET-FETCH (SQL 2012+)
DECLARE @Offset INT = (@PageIndex - 1) * @PageSize;
SELECT * FROM dbo.Orders
WHERE OrderDate >= '2024-01-01' AND Status = 1
ORDER BY OrderID DESC
OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY;
優勢:語法原生、優化器支持更好、無需動態 SQL、計劃穩定。
- 上一篇文章: 數據庫設計與 SQL Server 實踐的五大核心認知:大數據時代、完整性、安全性、系統觀與工程化
- 下一篇文章: SQL Server 觸發器完整操作指南:創建、修改、刪除、查看、魔法表與 6 大實戰案例
Copyright ©
程式碼之家 All Rights Reserved