Click here to Skip to main content
Licence 
First Posted 26 Mar 2007
Views 105,925
Bookmarked 124 times

SQL Server 2005 Paging Results

By | 19 Apr 2007 | Article
Using SQL Server to do paging of sql results.
 
Part of The SQL Zone sponsored by
See Also

Introduction

With SQL Server 2005, it is now a lot easier to use paged queries than in previous versions. I will be using the NorthWind database (mostly), so you can also use the examples I have provided. I will keep the examples simple; anything complex will only cause confusion. I will start with "traditional" methods such as SELECT, TOP, and then move on to the specific SQL Server 2005 paging examples.

Background

I was asked a question or a series of questions, "How would you do paging in a SQL? How would you do this with a lot of records, say, 10,000 or more?"

I thought about answers. To be more precise, I thought of more questions and this got me thinking, "This must be a common problem, every developer must have done or solved this. What about paging sizes and working with very large data sets? What about getting results from multiple tables?"

So, I decided to look into these questions with specific reference to SQL Server 2005. The following is by far the easiest way and should be used, but it is rarely this easy.

select * from mytable
Where ID between 20 and 30

SQL Top

SQL Top (returns records from the TOP of the result set) is very good at returning a set number of records from each end of a results set. The example below gets the top 10 customers by order qty. This is a very common question on forums. TOP can also pull a percentage of records, although this isn't discussed here.

select top 10 * from customers -- This is a very basic example.
select TOP 10 Customers.CustomerID, Customers.CompanyName, count(*) OrderCount
from Customers inner join Orders on Orders.CustomerID = Customers.CustomerID
GROUP BY Customers.CustomerID, Customers.CompanyName
ORDER BY OrderCount DESC

This is really useful. When you want to pull records 11 to 20 you could use temp tables.

-- SELECT First 30 records in to Temp table
SELECT TOP 30 * INTO
#TEMP
from Customers
ORDER BY CompanyName ASC

--Select Bottom 10 records in another temp table

SELECT TOP 10 * 
INTO #TEMP2
from #Temp
ORDER BY CompanyName DESC

-- GET THE RECORDS

SELECT * FROM #TEMP2

This is fine for the first few pages or the first few users. If you have users that want to return page after page after page, you end up getting 1000 records to return 10, which is not very efficient. You could also have placed an identity on the first temp table and used a SELECT statement as an alternative.

Alternative to TOP

There is an alternative to TOP, which is to use rowcount. Use rowcount with care, as it can lead you into all sorts of problems if it's not turned off.

SET rowcount 10
SELECT * from Customers
ORDER BY CompanyName

WITH, ROW_NUMBER and OVER

This is new to SQL Server 2005 and looks really useful. Below is an example to get records 20 to 29 from a results set. It might a bit strange at first, but I will go through the query so you'll see how simple it is.

With Cust AS
    ( SELECT CustomerID, CompanyName,
    ROW_NUMBER() OVER (order by CompanyName) as RowNumber 
    FROM Customers )
select *
from Cust
Where RowNumber Between 20 and 30

The WITH in SQL Server 2005 specifies a temporary named result, much like a temporary table in previous versions of SQL Server. However, the import parts are the ROW_NUMBER and the OVER statement, which create a row number on each row based on the Company name. This is like adding an identity seed to a temp table with an order by clause.

I hope you are still with me. If not, run the code and view the results. This is really very quick for large tables; I have been impressed with the speed on tables with over 250,000 records.

Putting it All Together in a Stored Procedure

Now we will put it all together in a Stored Procedure that can be used by your application. I won't show a .NET datagrid or similar control, as that is outside the scope of this article. The stored procedure below uses flexible page sizes and page numbers, so you can select any page at random. This is quite useful if you wish to jump ahead 10 pages to find a particular record. The paging for this example starts at page 1 rather than at page 0, but this can be easily changed.

CREATE PROC GetCustomersByPage

@PageSize int, @PageNumber int 

AS 

Declare @RowStart int 
Declare @RowEnd int 

if @PageNumber > 0 
Begin 

SET @PageNumber = @PageNumber -1 

SET @RowStart = @PageSize * @PageNumber + 1; 
SET @RowEnd = @RowStart + @PageSize - 1 ; 

With Cust AS 
     ( SELECT CustomerID, CompanyName, 
       ROW_NUMBER() OVER (order by CompanyName) as RowNumber 
       FROM Customers ) 

select * 
from Cust 
Where RowNumber >= @RowStart and RowNumber <= @RowEnd end

END

To run this, simply specify the page size and page number (GetCustomersByPage, @PageSize and @PageNumber) as shown below.

exec GetCustomersByPage 10, 1

History

  • Version 1.0 22/03/2007: Initial
  • Version 1.1 18/04/2007: Fixed issue with proc that gets 11 records after the 1st page

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Frank Kerrigan

Software Developer (Senior)

United Kingdom United Kingdom

Member

Follow on Twitter Follow on Twitter
Frank Kerrigan
 
Currently developing Insurance systems with SQL Server, ASP.NET, C#, ADO for a company in Glasgow Scotland. Very keen on OOP and NUNIT testing. Been in IT forever (20 years) in mix of development and supporting applications / servers. Worked for companies big and small and enjoyed both.
 
Developed in (newest first) : C#, Progress 4GL, ASP.NET, SQL TSQL, HTML, VB.NET, ASP, VB, VBscript, JavaScript, Oracle PSQL, perl, Access v1-2000, sybase/informi, Pic Controllers, 6502 (ask your dad).
 
Msc .Net Development Evenings www.gcu.ac.uk
MCAD Passed
MCP C# ASP.NET Web Applications
MCP SQL Server 2000
HND Computing
OND / HNC Electrical Engineering,

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralUse this Paging Method Pinmembermayurmv17:07 4 Sep '08  
QuestionRe: Use this Paging Method PinmemberEric Xue (brokensnow)15:07 8 Sep '10  
Generalwithout using a store procedure using ; Pinmemberndinges2:55 18 Apr '08  
GeneralThanks PinmemberMexi-Fry13:52 2 Mar '08  
GeneralI think my construction is better PinmemberMarek Mizov0:32 6 Jul '07  
GeneralRe: I think my construction is better PinmemberFrank Kerrigan0:13 19 Jul '07  
GeneralMillion rows benchmark PinmemberRoberto 'Obi-Wan' Colnaghi Junior7:18 11 Jun '07  
GeneralRe: Million rows benchmark PinmemberFrank Kerrigan1:34 18 Jun '07  
QuestionSoftware Packaging of C# Windows Application and MS Access Database PinmemberSebanMathews1:25 20 Apr '07  
QuestionStrange effect... PinmemberBenCoo6:23 12 Apr '07  
AnswerRe: Strange effect... PinmemberFrank Kerrigan3:12 17 Apr '07  
GeneralRe: Strange effect... PinmemberBenCoo4:27 17 Apr '07  
GeneralRe: Strange effect... PinmemberFrank Kerrigan1:39 18 Apr '07  
GeneralRe: Strange effect... PinmemberFrank Kerrigan23:24 18 Apr '07  
GeneralBETWEEN is inclusive Pinmembermike.griffin@entityspaces.net13:41 8 Apr '07  
GeneralRe: BETWEEN is inclusive PinmemberFrank Kerrigan3:13 17 Apr '07  
GeneralRe: BETWEEN is inclusive PinmemberFrank Kerrigan23:25 18 Apr '07  
GeneralVery nice Job PinmemberRoboTheToolMan5:29 8 Apr '07  
Thank you for sharing your code; this is something I've have been planning to learn and you have provided the incentive to do just that. I spend a lot of time in SQL as well as VB.NET. I normally don’t set limits to page size but can see how it can be very useful. An observation that I made while going through the code was that the first page returned records 1-10 and the next pages returned records 10-19, 20-29, etc. This may be the expected output that you desired however I would have expected 1-10, 11-20, etc. I seen where someone else pointed this out earlier however the suggested code appeared to be a different method and did not produce the results than I would have expected. Another observation was that when trying to create the procedure in MS SQL Server Management Studio Express I had to place a comma after this statement (@PageSize int,). Even though omission of a comma is a very minor thing, it could make it difficult for first time users that may not know what the problem is.
 
Since you have done such a great job on this procedure I simply added a few lines of code to produce the results of record paging of records 1-10, 11-20, etc. as well as code to check for and delete the procedure if it already exist.
 
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'GetCustomersByPage' AND type = 'P')
DROP PROCEDURE GetCustomersByPage
GO
 
CREATE PROC GetCustomersByPage
@PageSize int,
@PageNumber int
AS
Declare @RowStart int
Declare @RowEND int
if @PageNumber > 0
BEGIN
IF @PageNumber <=1
BEGIN
SET @RowEND = @RowStart + @PageSize +1
END
SET @PageNumber = @PageNumber -1
SET @RowStart = @PageSize * @PageNumber+1
SET @RowEnd = @RowStart + @PageSize - 1;
 
With Cust AS
( SELECT CustomerID, CompanyName,
ROW_NUMBER() OVER (ORDER BY CompanyName) AS RowNumber
FROM Customers )
SELECT * FROM Cust WHERE RowNumber Between @RowStart and @RowEND
END
GO
 
You can test the results b executing the three SQL commands below:
exec GetCustomersByPage 10, 1
exec GetCustomersByPage 10, 2
exec GetCustomersByPage 10, 3
 


GeneralNicely put PinmemberRFelts5:01 4 Apr '07  
GeneralI have been wondering about that forever Pinmemberphilmee9512:09 3 Apr '07  
Generalold problem - my solution - this will work for SQL 2K and 2K5 Pinmemberobriejoh6:39 3 Apr '07  
AnswerRe: old problem - my solution - this will work for SQL 2K and 2K5 PinmemberAbishek Bellamkonda13:49 3 Apr '07  
GeneralUsing Double Top Pinmemberhelitb1:51 3 Apr '07  
GeneralRe: Using Double Top Pinmemberemission0:31 15 Aug '08  
GeneralOld Problem and old solutions : But Brillantly articulated PinmemberAbishek Bellamkonda16:43 2 Apr '07  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120529.1 | Last Updated 19 Apr 2007
Article Copyright 2007 by Frank Kerrigan
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid