Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 540
David Avatar asked Sep 15 '11 19:09

David


People also ask

What does ROW_NUMBER () over do?

ROW_NUMBER function is a SQL ranking function that assigns a sequential rank number to each new record in a partition.

Is ROW_NUMBER faster than group by?

Row_Number() is rarely faster, and usually only due to bad indexing/heaps, or because the data is incredibly limited that it has to number before moving forward.

Can we use ROW_NUMBER without partition?

ROW_NUMBER() Function without Partition By clausePartition by clause is an optional part of Row_Number function and if you don't use it all the records of the result-set will be considered as a part of single record group or a single partition and then ranking functions are applied.

Can we use ROW_NUMBER without over?

The row_number() window function can be used without order by in over to arbitrarily assign a unique value to each row.


2 Answers

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.

like image 122
xanatos Avatar answered Oct 03 '22 23:10

xanatos


You want the count for the whole resultset right?

does this work speedwise?

SELECT *,(select MAX(RowNumber) from Props) as MaxRow 
FROM Props 
WHERE RowNumber BETWEEN ((@PageNumber - 1) * @PageSize) + 1 
    AND (@PageNumber * @PageSize);
like image 24
SQLMenace Avatar answered Oct 03 '22 22:10

SQLMenace