在不考虑存储过程中的页码的情况下分页数据并获取行数

Paging data and get row count with out considering the page number in stored procedure

我正在使用 SQL Server 2012。我需要在我的存储过程中进行分页。在客户端(网页),我需要获得所请求页面的存储过程的结果,并且我还需要不考虑页码的行数来设置具有该条件的页数。

例如,当我的SubscribeId是12345674时,我需要运行这个查询第二页十行的存储过程。

Create Procedure TestSelectBill  
    (@PageNumber int = 1 ,  
     @RowCount int = 10  ,
     @SubscribeId Int = 0)  
As  
Begin  
    Select *  
    From billing.BillMaster As BM  
    Where (Bm.SubscribeId = @SubscribeId)  
    Order by SubscribeId  
        Offset (@PageNumber - 1) * @RowCount Rows 
        Fetch Next @RowCount Rows Only;  
End  

我必须像这样执行这个存储过程:

Execute TestSelectBill  
        @PageNumber = 2, @RowCount int = 10, @SubscribeId = 12345674

想象一下,对于这个 SubscribeId = 123456574,我在 billing.BillMaster 中有 105 行。现在我需要向我的最终用户显示 10 行结果,我必须让他 select 1 到 11 之间的一页。

这意味着我需要知道这个条件存在多少行 SubscribeId = 123456574

我可以像下面的代码一样将存储过程更改为 return 行数:

Create Procedure TestSelectBill  
    (@PageNumber int = 1,  
     @RowCount int = 10,
     @SubscribeId Int = 0)  
As  
Begin  
    DECLARE @ROW_COUNT INT = 0

    -- Find Row Count for this condition
    Select   
        @ROW_COUNT = COUNT(*)  
    From 
        billing.BillMaster As BM  
    Where  
        (Bm.SubscribeId = @SubscribeId)  

    -- Select Result
    SELECT
        Row_Count = @ROW_COUNT,    
        *  
    FROM
        billing.BillMaster As BM  
    WHERE
        (Bm.SubscribeId = @SubscribeId)  
    ORDER BY
        SubscribeId  
        OFFSET ( @PageNumber - 1 ) * @RowCount ROWS  
        FETCH NEXT @RowCount ROWS ONLY;  
End  

但是如你所见,我的select要写两次,这样不好,因为修改和维护这个存储过程会很复杂。

此外,我可以将结果保存到临时 table 中,然后像下面的代码一样使用它:

CREATE Procedure TestSelectBill  
    (@PageNumber int = 1,  
     @RowCount int = 10,
     @SubscribeId Int = 0)  
As  
Begin  
    DECLARE @ROW_COUNT INT = 0

    -- Main Select 
    SELECT                      
        *  
    FROM 
        billing.BillMaster As BM  
    INTO 
        #T
    WHERE
        (Bm.SubscribeId = @SubscribeId)  

    -- Find Row Count for this condituion
    SELECT @ROW_COUNT = COUNT(*)  
    FROM #T

    -- Select Result
    SELECT
        Row_Count = @ROW_COUNT, 
        *  
    FROM
        #T
    ORDER BY 
        SubscribeId  
        OFFSET (@PageNumber - 1) * @RowCount ROWS  
        FETCH NEXT @RowCount ROWS ONLY;  
End  

但是正如您通过这种方式看到的那样,我使用的物理温度 table 当我在 main select 中有大量数据而没有分页时,它可能会非常慢。

谁能告诉我最好的方法吗?

您可以创建一个带有标识列的临时 table,该标识列对于插入的每一行递增 1,然后读取该列的最大值以获得行数。


-- First solution use count with window function
CREATE Procedure TestSelectBill  
    (@PageNumber int = 1,  
     @RowCount int = 10,
     @SubscribeId Int = 0)  
As  
Begin  
    SELECT
        COUNT(*) OVER(ORDER BY (SELECT NULL)) AS row_count ,
        *  
    FROM
        billing.BillMaster As BM  
    WHERE
        (Bm.SubscribeId = @SubscribeId)  
    ORDER BY
        SubscribeId  
        OFFSET (@PageNumber - 1) * @RowCount ROWS  
        FETCH NEXT @RowCount ROWS ONLY;  
End  
GO


-- Second solution: use dynamic sql with multiple result
Create Procedure TestSelectBill  
     @PageNumber int = 1,  
     @RowCount int = 10,
     @SubscribeId Int = 0
As  
Begin  

    DECLARE @params NVARCHAR(max) = '@PageNumber int, @RowCount int, @SubscribeId int'
    DECLARE @where NVARCHAR(max) = N' WHERE Bm.SubscribeId = @SubscribeId'
    DECLARE @stmt NVARCHAR(max) = N'SELECT COUNT(*) as row_cnt FROM billing.BillMaster As BM '
    DECLARE @stmt_rowcount NVARCHAR(max) = N'SELECT * FROM billing.BillMaster As BM '
    DECLARE @order_by NVARCHAR(max) = ' ORDER BY SubscribeId  
        OFFSET (@PageNumber - 1) * @RowCount ROWS  
        FETCH NEXT @RowCount ROWS ONLY;'

    SET @stmt += @where + @order_by
    SET @stmt_rowcount += @where

    -- First result set (rowcount)
    EXEC [sys].[sp_executesql]
        @stmt = @stmt_rowcount,
        @params = @params,
        @SubscribeId = @SubscribeId,
        @PageNumber = @PageNumber,
        @RowCount = @RowCount


    -- Second result set (data)
    IF @@ERROR = 0
    BEGIN
        EXEC [sys].[sp_executesql]
            @stmt = @stmt,
            @params = @params,
            @SubscribeId = @SubscribeId,
            @PageNumber = @PageNumber,
            @RowCount = @RowCount

    END

End  
GO