分页脚本的存储过程和输出参数(SQL Server 2008)

分页脚本的存储过程和输出参数(SQL Server 2008),sql,sql-server-2008-r2,Sql,Sql Server 2008 R2,我有下面的存储过程,只希望有一个SQL语句。目前您可以看到有两条语句,一条用于实际分页,另一条用于总记录计数,需要返回到我的应用程序进行分页 但是,由于我要从第一个查询中获取总行数,因此以下操作效率低下: COUNT(*) OVER(PARTITION BY 1) as TotalRows 如何将TotalRows设置为输出参数 ALTER PROCEDURE [dbo].[Nop_LoadAllOptimized] ( @PageSize int = null, @PageN

我有下面的存储过程,只希望有一个SQL语句。目前您可以看到有两条语句,一条用于实际分页,另一条用于总记录计数,需要返回到我的应用程序进行分页

但是,由于我要从第一个查询中获取总行数,因此以下操作效率低下:

COUNT(*) OVER(PARTITION BY 1) as TotalRows
如何将TotalRows设置为输出参数

ALTER PROCEDURE [dbo].[Nop_LoadAllOptimized]
(
    @PageSize int = null,
    @PageNumber int = null,
    @WarehouseCombinationID int = null,
    @CategoryId int = null,
    @OrderBy int = null,
    @TotalRecords int = null OUTPUT
)
AS
BEGIN

WITH Paging AS (
    SELECT rn = (ROW_NUMBER() OVER (
    ORDER BY 
        CASE WHEN @OrderBy = 0 AND @CategoryID IS NOT NULL AND @CategoryID > 0
        THEN pcm.DisplayOrder END ASC,
        CASE WHEN @OrderBy = 0
        THEN p.[Name] END ASC,
        CASE WHEN @OrderBy = 5
        THEN p.[Name] END ASC,
        CASE WHEN @OrderBy = 10
        THEN wpv.Price END ASC,
        CASE WHEN @OrderBy = 15
        THEN wpv.Price END DESC,
        CASE WHEN @OrderBy = 20
        THEN wpv.Price END DESC,
        CASE WHEN @OrderBy = 25
        THEN wpv.UnitPrice END ASC  
    )),COUNT(*) OVER(PARTITION BY 1) as TotalRows, p.*, pcm.DisplayOrder, wpv.Price, wpv.UnitPrice FROM Nop_Product p
    INNER JOIN Nop_Product_Category_Mapping pcm ON p.ProductID=pcm.ProductID
    INNER JOIN Nop_ProductVariant pv ON p.ProductID = pv.ProductID
    INNER JOIN Nop_ProductVariant_Warehouse_Mapping wpv ON pv.ProductVariantID = wpv.ProductVariantID
    WHERE pcm.CategoryID = @CategoryId
    AND (wpv.Published = 1 AND pv.Published = 1 AND p.Published = 1 AND p.Deleted = 0 AND pv.Deleted = 0 and wpv.Deleted = 0)
    AND wpv.WarehouseID IN (select WarehouseID from Nop_WarehouseCombination where UserWarehouseCombinationID = @WarehouseCombinationID)    
)
SELECT TOP (@PageSize) * FROM Paging PG
WHERE PG.rn > (@PageNumber * @PageSize) - @PageSize 

SELECT @TotalRecords = COUNT(p.ProductId) FROM Nop_Product p
INNER JOIN Nop_Product_Category_Mapping pcm ON p.ProductID=pcm.ProductID
INNER JOIN Nop_ProductVariant pv ON p.ProductID = pv.ProductID
INNER JOIN Nop_ProductVariant_Warehouse_Mapping wpv ON pv.ProductVariantID = wpv.ProductVariantID
WHERE pcm.CategoryID = @CategoryId
AND (wpv.Published = 1 AND pv.Published = 1 AND p.Published = 1 AND p.Deleted = 0 AND pv.Deleted = 0 and wpv.Deleted = 0)
AND wpv.WarehouseID IN (select WarehouseID from Nop_WarehouseCombination where UserWarehouseCombinationID = @WarehouseCombinationID)


END

我想我理解你的问题。你有没有考虑过可以在CTE之前进行清点 然后作为值作为变量传递给CTE

i、 e,预先设置@TotalRecords的值,然后传入,这样CTE将使用此计数,而不是第二次执行计数


这有意义吗,或者我没有领会你的意思。

如果要将查询分配给变量,我认为不运行两次查询是不行的

但是,您不能只添加另一列并执行类似的操作吗

;WITH Paging AS (select *,ROW_NUMBER() OVER(ORDER BY name) AS rn FROM sysobjects)

SELECT (SELECT MAX(rn) FROM Paging) AS TotalRecords,* FROM Paging
WHERE rn < 10

然后从前端抓取那个专栏

没问题,朋友,很可能我错过了一个技巧。然而,如果没有模式和数据,测试我的建议是很棘手的。在没有人给出更好的答案的情况下,我将这个测试脚本和数据放在一起演示我所说的内容。如果这不是你想要的,那没问题。如果它只是简单地错过了重点,那么我会把它放在下巴上

Declare @pagesize as int 
Declare @PageNumber as int 
Declare @TotalRowsOutputParm as int

SET @pagesize = 3
SET @PageNumber = 2;

--create some test data
DECLARE @SomeData  table
(
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [SomeValue] [nchar](10) NULL
) 

INSERT INTO @SomeData VALUES    ('TEST1')
INSERT INTO @SomeData VALUES    ('TEST2')
INSERT INTO @SomeData VALUES    ('TEST3')
INSERT INTO @SomeData VALUES    ('TEST4')
INSERT INTO @SomeData VALUES    ('TEST5')
INSERT INTO @SomeData VALUES    ('TEST6')
INSERT INTO @SomeData VALUES    ('TEST7')
INSERT INTO @SomeData VALUES    ('TEST8')
INSERT INTO @SomeData VALUES    ('TEST9')
INSERT INTO @SomeData VALUES    ('TEST10');

--Get total count of all rows
Set @TotalRowsOutputParm = (SELECT COUNT(SomeValue) FROM @SomeData p) ;

WITH Paging AS 
(    
   SELECT rn = (ROW_NUMBER() OVER (ORDER BY  SomeValue ASC)),
   @TotalRowsOutputParm as TotalRows, p.* 
   FROM [SomeData] p    
)

SELECT TOP (@PageSize) * FROM Paging PG
WHERE PG.rn > (@PageNumber * @PageSize) - @PageSize 

PRINT @TotalRowsOutputParm

最后,我决定只使用两个不同的SQL语句,一个用于count,一个用于select

“COUNT(*)OVER(PARTITION BY 1)as TotalRows”实际上非常昂贵,而且只使用两个不同的语句会快得多


谢谢所有帮助回答这个问题的人。

嗨,罗恩,我觉得你有点离题了。如果您在上面看到,第一个查询执行我的分页,但是在其中它还返回一列TotalRows。我想将其设置为我的输出参数,但我不确定如何设置,因此我正在下面进行第二次查询,以进行计数,其中显示“SELECT@TotalRecords=…”-我想去掉此项,并将@TotalRecords设置为等于第一次查询中的值“count(*)OVER(PARTITION BY 1)as TotalRows”,它不能是
MAX(PG.rn)
。您可能是指
MAX(rn)
。无论如何,由于您已经在使用
rn
,我认为添加TOP没有多大意义,除非使用TOP比只使用
WHERE PG.rn>(@PageNumber*@PageSize)-@PageSize和PG.rn Hi Ron更有效,谢谢您的时间,但是我仍然不认为这是我想要的。这不是在做两个select语句吗?理论上说是两次击中DB?这就是我现在正在做的,但我不想。我希望我的输出参数和结果集在一个SQL语句中。您好,是的,它进行了两次选择,但问题是它的效率要高得多,因为在我的示例中,您只计算一次行,而不是在示例中计算两次行。性能提升将是巨大的。我从你的问题中了解到这是你关心的问题。我同意它不能完全回答你,因为我的答案仍然包含2个选项,但我认为你会发现效率很高,因为计数可能是最大的成本。让我知道你的想法
Declare @pagesize as int 
Declare @PageNumber as int 
Declare @TotalRowsOutputParm as int

SET @pagesize = 3
SET @PageNumber = 2;

--create some test data
DECLARE @SomeData  table
(
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [SomeValue] [nchar](10) NULL
) 

INSERT INTO @SomeData VALUES    ('TEST1')
INSERT INTO @SomeData VALUES    ('TEST2')
INSERT INTO @SomeData VALUES    ('TEST3')
INSERT INTO @SomeData VALUES    ('TEST4')
INSERT INTO @SomeData VALUES    ('TEST5')
INSERT INTO @SomeData VALUES    ('TEST6')
INSERT INTO @SomeData VALUES    ('TEST7')
INSERT INTO @SomeData VALUES    ('TEST8')
INSERT INTO @SomeData VALUES    ('TEST9')
INSERT INTO @SomeData VALUES    ('TEST10');

--Get total count of all rows
Set @TotalRowsOutputParm = (SELECT COUNT(SomeValue) FROM @SomeData p) ;

WITH Paging AS 
(    
   SELECT rn = (ROW_NUMBER() OVER (ORDER BY  SomeValue ASC)),
   @TotalRowsOutputParm as TotalRows, p.* 
   FROM [SomeData] p    
)

SELECT TOP (@PageSize) * FROM Paging PG
WHERE PG.rn > (@PageNumber * @PageSize) - @PageSize 

PRINT @TotalRowsOutputParm