user1823901
user1823901

Reputation: 151

Return rows between a specific range, with one select statement

I'm looking to some expresion like this (using SQL Server 2008)

SELECT TOP 10 columName FROM tableName

But instead of that I need the values between 10 and 20. And I wonder if there is a way of doing it using only one SELECT statement.

For example this is useless:

SELECT columName FROM
(SELECT ROW_NUMBER() OVER(ORDER BY someId) AS RowNum, * FROM tableName) AS alias
WHERE RowNum BETWEEN 10 AND 20

Because the select inside brackets is already returning all the results, and I'm looking to avoid that, due to performance.

Upvotes: 15

Views: 59341

Answers (5)

user3688672
user3688672

Reputation: 1

You could create a temp table that is ordered the way you want like:

SELECT ROW_NUMBER() OVER(ORDER BY someId) AS RowNum, * FROM tableName into ##tempTable ...

That way you have an ordered list of rows. and can just query by row number the subsequent times instead of doing the inner query multiple times.

Upvotes: 0

Gordon Linoff
Gordon Linoff

Reputation: 1269603

There is a trick with row_number that does not involve sorting all the rows.

Try this:

SELECT columName
FROM (SELECT ROW_NUMBER() OVER(ORDER BY (select NULL as noorder)) AS RowNum, *
      FROM tableName
     ) as alias
WHERE RowNum BETWEEN 10 AND 20

You cannot use a constant in the order by. However, you can use an expression that evaluates to a constant. SQL Server recognizes this and just returns the rows as encountered, properly enumerated.

Upvotes: 10

Oleksandr Fedorenko
Oleksandr Fedorenko

Reputation: 16894

One more option

SELECT TOP(11) columName
FROM dbo.tableName
ORDER BY
CASE WHEN ROW_NUMBER() OVER (ORDER BY someId) BETWEEN 10 AND 20 
     THEN ROW_NUMBER() OVER (ORDER BY someId) ELSE NULL END DESC

Upvotes: 1

Laurence
Laurence

Reputation: 10976

Why do you think SQL Server would evaluate the entire inner query? Assuming your sort column is indexed, it'll just read the first 20 values. If you're really nervous you could do this:

Select
  Id 
From (
  Select Top 20 -- note top 20
    Row_Number() Over(Order By Id) As RowNum,
    Id 
  From
    dbo.Test
  Order By
    Id
  ) As alias
Where
  RowNum Between 10 And 20
Order By
  Id

but I'm pretty sure the query plan is the same either way.

(Really) Fixed as per Aaron's comment.

http://sqlfiddle.com/#!3/db162/6

Upvotes: 3

RAS
RAS

Reputation: 3385

Use SQL Server 2012 to fetch/skip!

SELECT SalesOrderID, SalesOrderDetailID, ProductID, OrderQty, UnitPrice, LineTotal
FROM AdventureWorks2012.Sales.SalesOrderDetail
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

There's nothing better than you're describing for older versions of sql server. Maybe use CTE, but unlikely to make a difference.

WITH NumberedMyTable AS
(
    SELECT
        Id,
        Value,
        ROW_NUMBER() OVER (ORDER BY Id) AS RowNumber
    FROM
        MyTable
)
SELECT
    Id,
    Value
FROM
    NumberedMyTable
WHERE 
    RowNumber BETWEEN @From AND @To  

or, you can remove top 10 rows and then get next 10 rows, but I double anyone would want to do that.

Upvotes: 10

Related Questions