0

我正在使用 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

想象一下,我billing.BillMaster为此有 105 行SubscribeId = 123456574。现在我需要向最终用户显示 10 行作为结果,我必须让他选择 1 到 11 之间的一页。

这意味着我需要知道这种情况存在多少行SubscribeId = 123456574

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

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  

但是正如你所见,我必须写两次我的选择,这并不好,因为修改和维护这个存储过程会非常复杂。

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

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  

但是正如您以这种方式看到的那样,当我在主选择中有大量数据而没有分页时,我使用的物理临时表可能会非常慢。

谁能告诉我最好的方法?

4

2 回答 2

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



于 2016-11-24T14:18:51.257 回答
0

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

于 2016-11-24T05:11:34.853 回答