Search code examples
sqlsql-servercommon-table-expressionrow-numberrowcount

CTE, ROW_NUMBER and ROWCOUNT


I am trying to return a page of data and also row count of all data in one stored procedure which looks like following:

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);

I am unable to return the row count (highest row number).

I know this has already been discussed (I've seen this: Efficient way of getting @@rowcount from a query using row_number) but when I add COUNT(x) OVER(PARTITION BY 1) in the CTE, the performance degrades and the query above that normally takes no time takes forever to execute. I reckon it's because the count is calculated for each row? I seems that I can't reuse the CTE in another query. Table Props has 100k records, CTE returns 5k records.


Solution

  • In T-SQL it should be

    ;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);
    

    now you have CNT in every line... Or you wanted something different? You wanted a second resultset with only the count? Then do it!

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

    Note: reedited, the query 1 David was referencing now has been trashcanned, query 2 is now query 1.