Ray
Ray

Reputation: 46595

Select TOP N and set variable if more could be selected

Is there a more efficient way of doing the following SQL?

I want to select the top 50 results, but I also want to set a variable to tell me if I would have gotten more results back without the TOP

DECLARE @MoreExists BIT
SET @MoreExists = 0

DECLARE @Count INT
SELECT @Count = Count(*) 
   FROM MyTable WHERE ... --some expensive where clause

IF @Count > 50
    SET @MoreExists = 1

SELECT TOP 50 Field1, Field2, ... 
    FROM MyTable WHERE ... --same expensive where clause

Upvotes: 0

Views: 1516

Answers (4)

Sam Saffron
Sam Saffron

Reputation: 131192

A spin on @Dougs answer

SET NOCOUNT ON 

SELECT TOP 51 Field1, Field2, ... 
    into #t
    FROM MyTable WHERE ... --same expensive where clause

if @@rowcount > 50 
      SET @MoreExists = 1

 SET NOCOUNT OFF

 SELECT TOP 50 Field1, Field2, ... 
    from #t
    -- maintain ordering with an order by clause

Upvotes: 2

Rob Farley
Rob Farley

Reputation: 15849

How about using COUNT(*) OVER... in a sub-query?

DECLARE @ReqCount int;
SET @ReqCount = 50;

SELECT TOP (@ReqCount) *
FROM 
(
SELECT *, Count(*) OVER() AS TotalCnt
FROM MyTable WHERE ...
) t
ORDER BY ...
;

And if you want to use ROW_NUMBER() too, then try:

SELECT *
FROM 
(
SELECT *, ROW_NUMBER() OVER (ORDER BY ...) AS RowNum, Count(*) OVER() AS TotalCnt
FROM MyTable WHERE ...
) t
WHERE RowNum BETWEEN @StartRange AND @EndRange
ORDER BY ...
;

And then you can easily check to see if TotalCnt > @ReqCount (or @EndRange), to be able to see if there are more to fetch.

Rob

Upvotes: 0

Mitch Wheat
Mitch Wheat

Reputation: 300797

Yes.

The common approach is to use ROW_NUMBER():

WITH MyTableEntries AS 
( 
    SELECT ROW_NUMBER() OVER (ORDER BY Date DESC) AS Row, col1, col2 
    FROM MyTable
    WHERE
          -- some expensive WHERE clause
)
SELECT col1, col2
FROM MyTableEntries 
WHERE Row BETWEEN(@PageIndex - 1) * @PageSize + 1 and @PageIndex*@PageSize

The efficient approach shown at this SqlServercentral article:

DECLARE @startRow INT ; SET @startrow = 50
;WITH cols
AS
(
    SELECT table_name, column_name, 
        ROW_NUMBER() OVER(ORDER BY table_name, column_name) AS seq, 
        ROW_NUMBER() OVER(ORDER BY table_name DESC, column_name desc) AS totrows
    FROM [INFORMATION_SCHEMA].columns
)
SELECT table_name, column_name, totrows + seq -1 as TotRows
FROM cols
WHERE seq BETWEEN @startRow AND @startRow + 49
ORDERBY seq

Upvotes: 0

Doug McClean
Doug McClean

Reputation: 14485

Select 51 results instead, use the top 50 in the client layer, and use the count to know if there are more.

Upvotes: 5

Related Questions