How to get N rows starting from row M from a sorted table in T-SQL
Promptly select N rows starting from row M by harnessing a CTE (Common Table Expression) with ROW_NUMBER()
to assign row numbers in a sorted order. Deploy a WHERE clause on the computed RowNum
to filter the rows. Remember to replace YourTable
, SortColumn
, M
, and N
to your matching table name, sorting column, starting row number, and number of rows you desire to pull, respectively. This method is a perfect candidate for paginated queries.
Getting the most performance with indexing
Dealing with large datasets is a common task in today’s data-loaded world. Guarantee that the SortColumn
is properly indexed. This can bring an appreciable performance boost, as the database engine can promptly sort and access the required rows, avoiding unnecessary table scans.
Database engines, like humans, love order and hate chaos. So, ensure your ROW_NUMBER()
function corresponds to an indexed column.
Fetching rows dynamically
For times when the starting row (M) and the number of rows (N) are variables, SQL provides OFFSET
and FETCH
. Here’s a fun alternative way using variables with dynamic OFFSET
and FETCH
:
This allows dynamic pagination where M
and N
can be specified at runtime.
Scaling up: Approaching large datasets
For times when performance is the chief concern or when dealing with large tables like your stockpile of cat GIFs, consider alternative pagination techniques and cross-table methods that can change performance from linear to logarithmic:
- A non-persistent cross-table, ordered by a clustered index.
- A combination of sorting, ROW_NUMBER, and filtering to optimize the dataset being processed.
- Taking advantage of server-side paging over large tables with cross-table techniques to boost efficiency.
Embracing precision with subqueries
For times when you require the maximum control over the rows chosen, enlist subqueries with NOT IN
.
Version compatibility
Beware, OFFSET
and FETCH
are available from SQL Server 2012 onwards. If you are using an older version, stick to ROW_NUMBER()
and CTE
or use SELECT TOP
in subqueries.
Was this article helpful?