【问题标题】:CTE, ROW_NUMBER and ROWCOUNTCTE、ROW_NUMBER 和 ROWCOUNT
【发布时间】:2011-11-18 04:49:01
【问题描述】:

我正在尝试在一个存储过程中返回一页数据以及所有数据的行数,如下所示:

WITH Props AS
(
    SELECT *,
    ROW_NUMBER() OVER (ORDER BY PropertyID) AS RowNumber
    FROM Property
    WHERE PropertyType = @PropertyType AND ...
)   

SELECT * FROM Props 
WHERE RowNumber BETWEEN ((@PageNumber - 1) * @PageSize) + 1 AND (@PageNumber * @PageSize);

我无法返回行数(最高行数)。

我知道这已经被讨论过(我见过这个: Efficient way of getting @@rowcount from a query using row_number) 但是当我在 CTE 中添加 COUNT(x) OVER(PARTITION BY 1) 时,性能会下降,并且上面的查询通常不需要时间来执行。我认为这是因为计数是针对每一行计算的?我似乎无法在另一个查询中重用 CTE。 Table Props 有 100k 条记录,CTE 返回 5k 条记录。

【问题讨论】:

  • 应该重新标记为 SQL Server 问题。我会为你做的,但你只能使用 5 个标签,而且我不知道你要删除哪个标签。

标签: sql sql-server common-table-expression row-number rowcount


【解决方案1】:

我遇到了同样的问题,想分享返回页面和总行数的代码。 临时表解决了这个问题。这是存储过程的主体:

DECLARE @personsPageTable TABLE(
  RowNumber INT, 
  PersonId INT, 
  FirstName NVARCHAR(50), 
  LastName NVARCHAR(50), 
  BirthDate DATE, 
  TotalCount INT);
    
        ;WITH PersonPage AS 
        (
            SELECT 
                 ROW_NUMBER() OVER(ORDER BY persons.Id) RowNumber,
                 Id,
                 FirstName,
                 LastName,
                 BirthDate
            FROM Persons
            WHERE BirthDate >= @BirthDateFrom AND BirthDate <= @BirthDateTo
        ), TotalCount AS( SELECT COUNT(*) AS [Count] FROM PersonPage)
        INSERT INTO @personsPageTable
        SELECT *, (select * from TotalCount) TotalCount FROM PersonPage
        ORDER BY PersonPage.RowNumber ASC
        OFFSET ((@pageNumber - 1) * @pageSize) ROWS
        FETCH NEXT @pageSize ROWS ONLY
    
        SELECT TOP 1 TotalCount FROM @personsPageTable
    
        SELECT 
            PersonId, 
            FirstName, 
            LastName, 
            BirthDate
        FROM @personsPageTable

如您所见,我将 CTE 结果和总行数 放入临时表并选择两个查询。第一次返回总计数,第二次返回带数据的页面。

【讨论】:

    【解决方案2】:

    在 T-SQL 中应该是

    ;WITH Props AS
    (
        SELECT *,
            ROW_NUMBER() OVER (ORDER BY PropertyID) AS RowNumber
        FROM Property
        WHERE PropertyType = @PropertyType AND ...
    )
    
    , Props2 AS
    (
        SELECT COUNT(*) CNT FROM Props
    )
    
    -- Now you can use even Props2.CNT
    SELECT * FROM Props, Props2
    WHERE RowNumber BETWEEN ((@PageNumber - 1) * @PageSize) + 1 AND (@PageNumber * @PageSize);
    

    现在你在每一行都有 CNT……或者你想要一些不同的东西?您想要第二个只有计数的结果集?那就去做吧!

    -- This could be the second result-set of your query.
    SELECT COUNT(*) CNT
    FROM Property
    WHERE PropertyType = @PropertyType AND ...
    

    注意:已重新编辑,David 现在引用的查询 1 已被回收,查询 2 现在是查询 1。

    【讨论】:

    • 1.不起作用,因为您必须在其中包含一个 group by 子句。 2. 效果很好,我最喜欢它。谢谢。
    • 在我的版本中,我在第一个 cte 中添加了 COUNT(1),导致工作台上的 800000 次读取。使用第二个 cte(就像您在此处所做的那样)跳过了所有这些读取,从而产生了极快的查询。
    【解决方案3】:

    您想要整个结果集的计数吗?

    这能快速工作吗?

    SELECT *,(select MAX(RowNumber) from Props) as MaxRow 
    FROM Props 
    WHERE RowNumber BETWEEN ((@PageNumber - 1) * @PageSize) + 1 
        AND (@PageNumber * @PageSize);
    

    【讨论】:

      猜你喜欢
      • 2014-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 2015-03-29
      • 2021-02-19
      • 1970-01-01
      相关资源
      最近更新 更多