在不考虑存储过程中的页码的情况下分页数据并获取行数
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
我正在使用 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