Row Offset in SQL Server

Viewed 239998

Is there any way in SQL Server to get the results starting at a given offset? For example, in another type of SQL database, it's possible to do:

SELECT * FROM MyTable OFFSET 50 LIMIT 25

to get results 51-75. This construct does not appear to exist in SQL Server.

How can I accomplish this without loading all the rows I don't care about? Thanks!

17 Answers

This is one way (SQL2000)

SELECT * FROM
(
    SELECT TOP (@pageSize) * FROM
    (
        SELECT TOP (@pageNumber * @pageSize) *
        FROM tableName 
        ORDER BY columnName ASC
    ) AS t1 
    ORDER BY columnName DESC
) AS t2 
ORDER BY columnName ASC

and this is another way (SQL 2005)

;WITH results AS (
    SELECT 
        rowNo = ROW_NUMBER() OVER( ORDER BY columnName ASC )
        , *
    FROM tableName 
) 
SELECT * 
FROM results
WHERE rowNo between (@pageNumber-1)*@pageSize+1 and @pageNumber*@pageSize

You can use ROW_NUMBER() function to get what you want:

SELECT *
FROM (SELECT ROW_NUMBER() OVER(ORDER BY id) RowNr, id FROM tbl) t
WHERE RowNr BETWEEN 10 AND 20

Depending on your version ou cannot do it directly, but you could do something hacky like

select top 25 *
from ( 
  select top 75 *
  from   table 
  order by field asc
) a 
order by field desc 

where 'field' is the key.

In SqlServer2005 you can do the following:

DECLARE @Limit INT
DECLARE @Offset INT
SET @Offset = 120000
SET @Limit = 10

SELECT 
    * 
FROM
(
   SELECT 
       row_number() 
   OVER 
      (ORDER BY column) AS rownum, column2, column3, .... columnX
   FROM   
     table
) AS A
WHERE 
 A.rownum BETWEEN (@Offset) AND (@Offset + @Limit-1) 

With SQL Server 2012 (11.x) and later and Azure SQL Database, you can also have "fetch_row_count_expression", you can also have ORDER BY clause along with this.

USE AdventureWorks2012;  
GO  
-- Specifying variables for OFFSET and FETCH values    
DECLARE @skip int = 0  , @take int = 8;  
SELECT DepartmentID, Name, GroupName  
FROM HumanResources.Department  
ORDER BY DepartmentID ASC   
    OFFSET @skip ROWS   
    FETCH NEXT @take ROWS ONLY; 

https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-ver15

Note OFFSET Specifies the number of rows to skip before it starts to return rows from the query expression. It is NOT the starting row number. So, it has to be 0 to include first record.

I've been searching for this answer for a while now (for generic queries) and found out another way of doing it on SQL Server 2000+ using ROWCOUNT and cursors and without TOP or any temporary table.

Using the SET ROWCOUNT [OFFSET+LIMIT] you can limit the results, and with cursors, go directly to the row you wish, then loop 'till the end.

So your query would be like this:

SET ROWCOUNT 75 -- (50 + 25)
DECLARE MyCursor SCROLL CURSOR FOR SELECT * FROM pessoas
OPEN MyCursor
FETCH ABSOLUTE 50 FROM MyCursor -- OFFSET
WHILE @@FETCH_STATUS = 0 BEGIN
    FETCH next FROM MyCursor
END
CLOSE MyCursor
DEALLOCATE MyCursor
SET ROWCOUNT 0

Method 1:

Ordering seem to matter here

Bringing limit before offset seems to work.

SELECT *
FROM MyTable
LIMIT 25
OFFSET 50

Method 2:

Alternatively, you can use limit only
LIMIT takes two values
1st: Offset value
2nd: No of rows to be displayed

SELECT *
FROM MyTable
LIMIT (OffsetValue), (NoOfRows)

SELECT *
FROM MyTable
LIMIT 50, 25
Related