SQLSERVER分页存储过程
在 SQL Server 中,分页存储过程用于高效查询大量数据中的某一页记录(如网页中的分页展示)。以下是一个通用的分页存储过程实现,支持动态表名、排序、条件筛选,并返回总记录数,适用于大多数场景。
分页存储过程实现
该存储过程使用 ROW_NUMBER()
函数(兼容 SQL Server 2005+)实现分页,同时返回当前页数据和总记录数,方便前端计算总页数。
CREATE PROCEDURE usp_GetPagedData@TableName NVARCHAR(100), -- 要查询的表名或视图名@OrderBy NVARCHAR(100), -- 排序字段(如 'ID DESC, Name ASC')@PageIndex INT = 1, -- 页码(默认第1页)@PageSize INT = 10, -- 每页记录数(默认10条)@Where NVARCHAR(1000) = '', -- 查询条件(如 'Status = 1 AND CreateTime > ''2023-01-01''')@TotalCount INT OUTPUT -- 输出参数:总记录数 AS BEGINSET NOCOUNT ON; -- 不返回计数信息,提升性能 BEGIN TRY-- 拼接查询总记录数的SQLDECLARE @CountSql NVARCHAR(1000) = 'SELECT @Total = COUNT(*) FROM ' + @TableName + CASE WHEN @Where <> '' THEN ' WHERE ' + @Where ELSE '' END; -- 执行总记录数查询EXEC sp_executesql @CountSql, N'@Total INT OUTPUT', @Total = @TotalCount OUTPUT; -- 计算分页起始位置(ROW_NUMBER()从1开始)DECLARE @StartRow INT = (@PageIndex - 1) * @PageSize + 1;DECLARE @EndRow INT = @PageIndex * @PageSize; -- 拼接分页查询SQL(使用ROW_NUMBER()实现)DECLARE @PagedSql NVARCHAR(2000) = 'WITH PagedData AS (SELECT *, ROW_NUMBER() OVER (ORDER BY ' + @OrderBy + ') AS RowNum FROM ' + @TableName + CASE WHEN @Where <> '' THEN ' WHERE ' + @Where ELSE '' END + ')SELECT * FROM PagedData WHERE RowNum BETWEEN ' + CAST(@StartRow AS NVARCHAR) + ' AND ' + CAST(@EndRow AS NVARCHAR) + 'ORDER BY RowNum'; -- 执行分页查询并返回结果EXEC sp_executesql @PagedSql;END TRYBEGIN CATCH-- 捕获并返回错误信息SELECT ERROR_NUMBER() AS ErrorNumber,ERROR_MESSAGE() AS ErrorMessage,ERROR_LINE() AS ErrorLine;END CATCH END
存储过程参数说明
参数名 | 类型 | 说明 |
---|---|---|
@TableName | NVARCHAR(100) | 必需,要查询的表名或视图名(如 'Customers' ) |
@OrderBy | NVARCHAR(100) | 必需,排序条件(如 'ID DESC' 或 'CreateTime ASC, Name DESC' ) |
@PageIndex | INT | 可选,页码(默认 1,即第一页) |
@PageSize | INT | 可选,每页记录数(默认 10 条) |
@Where | NVARCHAR(1000) | 可选,查询条件(无需加 WHERE 关键字,如 'Status = 1' ) |
@TotalCount | INT OUTPUT | 输出参数,返回符合条件的总记录数(用于计算总页数) |
使用示例
假设查询 Orders
表中,状态为 1(已付款)的订单,按创建时间倒序排列,查询第 2 页,每页 20 条记录:
DECLARE @Total INT; -- 接收总记录数 -- 调用分页存储过程 EXEC usp_GetPagedData@TableName = 'Orders',@OrderBy = 'CreateTime DESC',@PageIndex = 2,@PageSize = 20,@Where = 'Status = 1',@TotalCount = @Total OUTPUT; -- 输出总记录数 PRINT '总记录数:' + CAST(@Total AS NVARCHAR);
执行后会返回两个结果:
第 2 页的 20 条订单数据;
总记录数(通过
@Total
输出)。
优化与注意事项
性能优化:
确保
@OrderBy
中使用的字段有索引(如CreateTime
字段建立索引),避免全表扫描。对于超大表(千万级以上),可考虑使用OFFSET FETCH(SQL Server 2012+ 支持),语法更简洁:
SELECT * FROM Orders WHERE Status = 1 ORDER BY CreateTime DESC OFFSET (@PageIndex - 1) * @PageSize ROWS FETCH NEXT @PageSize ROWS ONLY;
安全注意:
该存储过程使用动态 SQL,存在 SQL 注入风险。生产环境中需验证
@TableName
、@OrderBy
等参数的合法性(如检查表名是否存在于系统表sys.tables
中)。
复杂查询:
若需关联多表查询,可先创建视图,再对视图使用该存储过程。
总记录数:
总记录数
@TotalCount
可用于前端计算总页数(总页数 = CEILING(总记录数 / 每页条数)
)。
通过该存储过程,可灵活实现各种场景下的分页查询,兼顾兼容性和易用性。根据实际业务需求,可进一步扩展参数(如返回字段筛选、关联查询等)。