首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 通用分頁存儲過程:ROW_NUMBER 動態 SQL 實現與參數化設計

     編輯:關於SqlServer

存儲過程完整代碼

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;

設計要點與改進建議

現代替代: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、計劃穩定。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方面當前實現改進方向
SQL 注入風險動態拼接表名/列名/WHERE白名單驗證表名/列名;WHERE 條件改用參數化或 TVP 傳遞
性能:深分頁ROW_NUMBER 全排序後過濾大表深分頁改用 Keyset Pagination(WHERE Pk > @LastPk ORDER BY Pk LIMIT N)
排序靈活性單列 DESC 固定增加 @OrderBy 參數,支持多列、ASC/DESC
統計一致性查詢與統計分兩次執行並發高時可能不一致,可用快照隔離或合併 CTE
計劃緩存動態 SQL 每次不同文本參數化 WHERE 值、固定表名/列名模式,利用計劃復用