Sql server 基于参数(不包括pagesize参数)的参数化存储过程分页返回行计数
我希望能够从存储过程中获取查询的行数,但不考虑分页的pagesize限制 以下是我的存储过程:Sql server 基于参数(不包括pagesize参数)的参数化存储过程分页返回行计数,sql-server,tsql,stored-procedures,parameters,Sql Server,Tsql,Stored Procedures,Parameters,我希望能够从存储过程中获取查询的行数,但不考虑分页的pagesize限制 以下是我的存储过程: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[OrderLoadAllPaged] @OrderId INT = 0, @WarehouseId INT = 0, @PaymentMethodSystemName NVARCHAR(MAX) = NULL, @OrderS
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[OrderLoadAllPaged]
@OrderId INT = 0,
@WarehouseId INT = 0,
@PaymentMethodSystemName NVARCHAR(MAX) = NULL,
@OrderStatusId INT = 0,
@PaymentStatusId INT = 0,
@ShippingStatusId INT = 0,
@BillingEmail NVARCHAR(MAX) = NULL,
@BillingFirstName NVARCHAR(MAX) = NULL,
@BillingLastName NVARCHAR(MAX) = NULL,
@ShippingMethod NVARCHAR(MAX) = NULL,
@CreatedFromUtc DATETIME = NULL,
@CreatedToUtc DATETIME = NULL,
@PageIndex INT = 0,
@PageSize INT = 2147483644,
@TotalRecords INT = NULL OUTPUT
AS
BEGIN
DECLARE @sql NVARCHAR(MAX)
SET NOCOUNT ON;
SELECT TOP (@PageSize) *
FROM [Test].[dbo].[Order] o WITH (NOLOCK)
LEFT JOIN
(SELECT *
FROM [Test].[dbo].[Address] a
WHERE (@BillingEmail IS NULL OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS NULL OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS NULL OR a.[LastName] = @BillingLastName)) a
ON a.Id = o.BillingAddressId
AND o.[Deleted] = 0
AND (o.[Id] = @OrderId OR @OrderId = 0)
AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
AND (@PaymentMethodSystemName IS NULL OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
AND (@ShippingMethod IS NULL OR o.[ShippingMethod] = @ShippingMethod)
AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
AND o.[Id] >= @PageIndex
AND o.[Id] < @PageSize
ORDER BY
o.[CreatedOnUtc] DESC
-- OFFSET @PageIndex ROWS FETCH NEXT @PageSize ROWS ONLY
--total records
SET @TotalRecords = @@rowcount
END
更新
我有分页的工作,但它不太正确。它从我的订单表返回记录的总数,但这就像插入到TENTOTAL表中的参数被忽略一样。我想我弄错了
代码如下:
create table #TempTotal (RowNum int identity(1,1), id int);
create index #IK_temp on #TempTotal (id);
-- Insert statements for procedure here
--select all
INSERT INTO #TempTotal ([id])
SELECT o.[Id]
FROM [Test].[dbo].[Order] o with (NOLOCK)
left join
(select * from [Test].[dbo].[Address] a
where (@BillingEmail IS null OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)) a
ON a.Id = o.BillingAddressId
AND o.[Deleted] = 0
AND (o.[Id] = @OrderId OR @OrderId = 0)
AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
AND (@PaymentMethodSystemName IS NULL OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
AND (@ShippingMethod IS NULL OR o.[ShippingMethod] = @ShippingMethod)
AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
ORDER BY o.[CreatedOnUtc] DESC
-- Return the paged records
select TOP (@PageSize) *
from [Test].[dbo].[Order] ord
where ord.Id in (
select id
from #TempTotal
Where (ord.[Id] >= @PageIndex AND ord.[Id] < @PageSize)
)
ORDER BY ord.[CreatedOnUtc] DESC;
更新3
我还必须更新分页以计算索引,我的cms将pageindex发送为page1、2、3等等。你的情况可能需要类似的东西。完整代码如下所示:
有两种选择:
复制不带顶部的查询以获取计数*
按原样使用查询以获取id并将其插入包含标识列RowNum的临时表中,然后使用该列进行分页,然后在获取实际记录之前获取计数,例如
选项2的性能将显著提高,因为它减少了SQL Server必须处理的数据量
作为旁白,您永远不应该选择*因为它会导致意外的、潜在的不良行为。始终列出您的列。有几个选项:
复制不带顶部的查询以获取计数*
按原样使用查询以获取id并将其插入包含标识列RowNum的临时表中,然后使用该列进行分页,然后在获取实际记录之前获取计数,例如
选项2的性能将显著提高,因为它减少了SQL Server必须处理的数据量
作为旁白,您永远不应该选择*因为它会导致意外的、潜在的不良行为。始终列出您的列。尝试使用CTE
SET @lFirstRec = ( @PageIndex – 1 ) * @PageSize
SET @lLastRec = ( @PageIndex * @PageSize + 1 )
SET @lTotalRows = @lFirstRec – @lLastRec + 1
; WITH CTE_Results
AS (
SELECT ROW_NUMBER() OVER (ORDER BY o.Id
) AS ROWNUM,
Count(*) over () AS TotalCount,
*
from [Test].[dbo].[Address] a
where (@BillingEmail IS null OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)) a
ON a.Id = o.BillingAddressId
AND
o.[Deleted] = 0
AND (o.[Id] = @OrderId OR @OrderId = 0)
AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
AND (@PaymentMethodSystemName IS null OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
AND (@ShippingMethod IS null OR o.[ShippingMethod] = @ShippingMethod)
AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
)
SELECT
TotalCount,
ROWNUM,
CPC.*
FROM CTE_Results AS CPC
WHERE
ROWNUM > @lFirstRec
AND ROWNUM < @lLastRec
ORDER BY CPC.CreatedOnUtc DESC, ROWNUM ASC
有关方法的更多详细信息,请参阅:
试试CTE
SET @lFirstRec = ( @PageIndex – 1 ) * @PageSize
SET @lLastRec = ( @PageIndex * @PageSize + 1 )
SET @lTotalRows = @lFirstRec – @lLastRec + 1
; WITH CTE_Results
AS (
SELECT ROW_NUMBER() OVER (ORDER BY o.Id
) AS ROWNUM,
Count(*) over () AS TotalCount,
*
from [Test].[dbo].[Address] a
where (@BillingEmail IS null OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)) a
ON a.Id = o.BillingAddressId
AND
o.[Deleted] = 0
AND (o.[Id] = @OrderId OR @OrderId = 0)
AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
AND (@PaymentMethodSystemName IS null OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
AND (@ShippingMethod IS null OR o.[ShippingMethod] = @ShippingMethod)
AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
)
SELECT
TotalCount,
ROWNUM,
CPC.*
FROM CTE_Results AS CPC
WHERE
ROWNUM > @lFirstRec
AND ROWNUM < @lLastRec
ORDER BY CPC.CreatedOnUtc DESC, ROWNUM ASC
有关方法的更多详细信息,请参阅:
@chrisc我不能在看不到实际代码的情况下判断发生了什么,但是如果操作正确,它应该给出与分页之前相同的行数。如果你把它分解并测试一下,解决它应该不会太难。是的,删除临时表可能是一个好主意,它们确实会随着连接自动删除,但是专门删除它们是一个很好的做法。我非常确定,您已经创建了一个巨大的连接,并且o.[Deleted]=0应该在o.[Deleted]的位置 = 0@chrisc注意,我更改了临时表索引-我最初给出的索引是用于不同的内容。@chrisc再次更新以使用偏移量。。。fetch next是推荐的方法。仍然会在同一时间生成相同的结果。使用推荐的方法offset@PageStart-1 rows fetch next@Pagesize rows,运行速度会更快only@chrisc在看不到实际代码的情况下,我无法判断发生了什么,但如果操作正确,它将给出与分页之前相同的行数。如果你把它分解并测试一下,解决它应该不会太难。是的,删除临时表可能是一个好主意,它们确实会随着连接自动删除,但是专门删除它们是一个很好的做法。我非常确定,您已经创建了一个巨大的连接,并且o.[Deleted]=0应该在o.[Deleted]的位置 = 0@chrisc注意,我更改了临时表索引-我最初给出的索引是用于不同的内容。@chrisc再次更新以使用偏移量。。。fetch next是推荐的方法。仍然在同一时间生成相同的结果。使用推荐的方法offset@PageStart-1 rows fetch next@Pagesize rows,运行速度会更快
-- Return the paged records
select TOP (@PageSize) *
from [Test].[dbo].[Order] ord
where ord.Id in (
select id
from #TempTotal
Where (ord.[Id] > @PageIndex)
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[OrderLoadAllPaged]
@OrderId INT = 0,
@WarehouseId INT = 0,
@PaymentMethodSystemName NVARCHAR(MAX) = NULL,
@OrderStatusId INT = 0,
@PaymentStatusId INT = 0,
@ShippingStatusId INT = 0,
@BillingEmail NVARCHAR(MAX) = NULL,
@BillingFirstName NVARCHAR(MAX) = NULL,
@BillingLastName NVARCHAR(MAX) = NULL,
@ShippingMethod NVARCHAR(MAX) = NULL,
@CreatedFromUtc DATETIME = NULL,
@CreatedToUtc DATETIME = NULL,
@PageIndex INT = 0,
@PageSize INT = 2147483644,
@TotalRecords INT = NULL OUTPUT
AS
BEGIN
DECLARE @sql NVARCHAR(MAX)
SET NOCOUNT ON;
create table #TempTotal (RowNum int identity(1,1), id int);
create index #IK_temp on #TempTotal (RowNum);
-- Insert statements for procedure here
--select all
INSERT INTO #TempTotal ([id])
SELECT o.[Id]
FROM [Test].[dbo].[Order] o with (NOLOCK)
LEFT join [Test].[dbo].[Address] a on a.Id = o.BillingAddressId and (
coalesce(@BillingEmail,'') <> ''
or coalesce(@BillingFirstName,'') <> ''
or coalesce(@BillingLastName,'') <> ''
)
WHERE (@BillingEmail IS null OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)
AND o.[Deleted] = 0
AND (o.[Id] = @OrderId OR @OrderId = 0)
AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
AND (@PaymentMethodSystemName IS NULL OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
AND (@ShippingMethod IS NULL OR o.[ShippingMethod] = @ShippingMethod)
AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
ORDER BY o.[CreatedOnUtc] DESC;
--paging
DECLARE @PageLowerBound int
SET @PageLowerBound = @PageSize * @PageIndex
-- Return the paged records
select TOP (@PageSize) *
from [Test].[dbo].[Order] ord
where ord.[Id] in (
select id
from #TempTotal tt
Where (tt.RowNum > @PageLowerBound)
)ORDER BY ord.[CreatedOnUtc] DESC;
--total records
select @TotalRecords = count(*) from #TempTotal; -- To get the total record count
DROP TABLE #TempTotal
END
create table #temp (id int, RowNum int identity(1,1));
create index #IK_temp on #temp (RowNum);
-- insert your ids from your full query here
-- Assign your total record count
select @TotalRecords = count(*) from #temp; -- To get the total record count
-- Return the paged records
select *
from MyTable
where id in (
select id
from #temp
order by RowNum asc
offset (@PageStart-1) rows fetch next @Pagesize rows only
);
SET @lFirstRec = ( @PageIndex – 1 ) * @PageSize
SET @lLastRec = ( @PageIndex * @PageSize + 1 )
SET @lTotalRows = @lFirstRec – @lLastRec + 1
; WITH CTE_Results
AS (
SELECT ROW_NUMBER() OVER (ORDER BY o.Id
) AS ROWNUM,
Count(*) over () AS TotalCount,
*
from [Test].[dbo].[Address] a
where (@BillingEmail IS null OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)) a
ON a.Id = o.BillingAddressId
AND
o.[Deleted] = 0
AND (o.[Id] = @OrderId OR @OrderId = 0)
AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
AND (@PaymentMethodSystemName IS null OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
AND (@ShippingMethod IS null OR o.[ShippingMethod] = @ShippingMethod)
AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
)
SELECT
TotalCount,
ROWNUM,
CPC.*
FROM CTE_Results AS CPC
WHERE
ROWNUM > @lFirstRec
AND ROWNUM < @lLastRec
ORDER BY CPC.CreatedOnUtc DESC, ROWNUM ASC