简体   繁体   English

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

[英]Stored Procedure and output parameter from paging script (SQL Server 2008)

I have the below stored procedure and would like to only have one SQL statement. 我有下面的存储过程,并希望只有一个SQL语句。 At the moment you can see there are two statements, one for the actual paging and one for a count of the total records which needs to be return to my app for paging. 目前您可以看到有两个语句,一个用于实际的分页,另一个用于需要返回到我的应用程序进行分页的总记录数。

However, the below is inefficient as I am getting the total rows from the first query: 但是,由于我从第一个查询获取总行数,因此下面的效率很低:

COUNT(*) OVER(PARTITION BY 1) as TotalRows

How can I set TotalRows as my output parameter? 如何将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

I think I understand your issue here. 我想我在这里理解你的问题。 Have you considered that the Count could be done BEFORE the CTE and then passed in as value to the CTE as a variable. 您是否认为计数可以在CTE之前完成,然后作为变量传递给CTE作为值。

ie, set the value for @TotalRecords up front, pass it in, and so the CTE will use this count rather than executing the count a second time? 即,预先设置@TotalRecords的值,传入,然后CTE将使用此计数而不是第二次执行计数?

Does this make sense, or have I missed your point here. 这是否有意义,或者我在这里错过了你的观点。

no problem friend, highly possible i missed a trick here. 没问题的朋友,我极有可能在这里错过了一招。 However without the schema and data its tricky to test what I am suggesting. 但是,如果没有架构和数据,那么测试我的建议就很棘手。 In the absence of someone giving a better answer, I've put this test script with data together to demo what I am talking about. 在没有人给出更好的答案的情况下,我将这个测试脚本与数据放在一起来演示我正在谈论的内容。 If this isn't what you want then no problem. 如果这不是你想要的那么没问题。 If it is just plain missing the point again, then I'll take that on the chin. 如果它再次明显地忽略了这一点,那么我会把它放在下巴上。

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

I don't think you can do it without running the query twice if you want to assign it to a variable 如果你想将它分配给一个变量,我认为如果不运行两次查询就不能这样做

however, can't you just add another column and do something like this instead? 但是,您不能只添加另一列并执行此类操作吗?

;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

Or in your case 或者在你的情况下

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

Then from the front end grab that column 然后从前端抓住那一列

In the end I decided just to use two different SQL statements, one for count, one for select. 最后我决定使用两个不同的SQL语句,一个用于计数,一个用于select。

The "COUNT(*) OVER(PARTITION BY 1) as TotalRows" actually was pretty expensive and it turned out much quicker to just use two different statements. “COUNT(*)OVER(PARTITION BY 1)作为TotalRows”实际上非常昂贵,而且使用两个不同的语句更快。

Thank you everyone who helped with this question. 谢谢所有帮助过这个问题的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM