Tsoukias
asked on
Problem regarding stored procedure paging.
We are using SQL 2000 and have many pages where we required stored proc paging. We're currently using this template to provide our paging:
CREATE PROCEDURE [dbo].[usp_PageResults_NAI ]
(
@startRowIndex int,
@maximumRows int
)
AS
DECLARE @first_id int, @startRow int
-- A check can be added to make sure @startRowIndex isn't > count(1)
-- from employees before doing any actual work unless it is guaranteed
-- the caller won't do that
-- Get the first employeeID for our page of records
SET ROWCOUNT @startRowIndex
SELECT @first_id = employeeID FROM employees ORDER BY employeeid
-- Now, set the row count to MaximumRows and get
-- all records >= @first_id
SET ROWCOUNT @maximumRows
SELECT e.*, d.name as DepartmentName
FROM employees e
INNER JOIN Departments D ON
e.DepartmentID = d.DepartmentID
WHERE employeeid >= @first_id
ORDER BY e.EmployeeID
SET ROWCOUNT 0
GO
This method is very fast and easy to use but the problem with it is that it stores the unique column ID as a start and end point on where to get page 2, page 3 etc. It only works when you're bring back results that are ASC or DESC on a incremental unique column.
We want to find a very fast solution to paging like this but with different sorting. We want to bring back members who have updated their profile recently, or were online, which means their unique id's won't be incremental anymore.
A) Is it wise to use the above paging method for columns other than unique ID's and if so, how would we go about it.
B) Is there a better paging solution out there?
CREATE PROCEDURE [dbo].[usp_PageResults_NAI
(
@startRowIndex int,
@maximumRows int
)
AS
DECLARE @first_id int, @startRow int
-- A check can be added to make sure @startRowIndex isn't > count(1)
-- from employees before doing any actual work unless it is guaranteed
-- the caller won't do that
-- Get the first employeeID for our page of records
SET ROWCOUNT @startRowIndex
SELECT @first_id = employeeID FROM employees ORDER BY employeeid
-- Now, set the row count to MaximumRows and get
-- all records >= @first_id
SET ROWCOUNT @maximumRows
SELECT e.*, d.name as DepartmentName
FROM employees e
INNER JOIN Departments D ON
e.DepartmentID = d.DepartmentID
WHERE employeeid >= @first_id
ORDER BY e.EmployeeID
SET ROWCOUNT 0
GO
This method is very fast and easy to use but the problem with it is that it stores the unique column ID as a start and end point on where to get page 2, page 3 etc. It only works when you're bring back results that are ASC or DESC on a incremental unique column.
We want to find a very fast solution to paging like this but with different sorting. We want to bring back members who have updated their profile recently, or were online, which means their unique id's won't be incremental anymore.
A) Is it wise to use the above paging method for columns other than unique ID's and if so, how would we go about it.
B) Is there a better paging solution out there?
ASKER
That solution looks definitely along the lines of what I was hoping for - but I forgot to mention that ideally I'd like a dynamic solution, ie, passing in the column I wanted to order/sort on? Is this going to be possible?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
First, adapt your given example to dyanamically generate rownumber independent of the employeeID. That looks like this:
CREATE PROCEDURE [dbo].[usp_PageResults_NAI
(
@startRowIndex int,
@maximumRows int
)
AS
SELECT e.*, d.name as DepartmentName
--derive ordinal rownum from employeeID sequence, which is a unique key
, (select count (*)+1 from FROM employees e2
inner join departments d2 on e2.departmentID = d2.departmentID
where e2.employeeID < e.employeeID
) as rownum
FROM employees e
INNER JOIN Departments D ON
e.DepartmentID = d.DepartmentID
WHERE rownum between @startRowIndex and (@startRowIndex + @maximumRows - 1)
ORDER BY e.EmployeeID
Then expand to support a different sort. For this example, I will sort by Dept Name
CREATE PROCEDURE [dbo].[usp_PageResults_NAI
(
@startRowIndex int,
@maximumRows int
)
AS
SELECT e.*, d.name as DepartmentName
--derive ordinal rownum, this time from name. Since name is not unique, use the unique key
--employeeID as a tie breaker
, (select count (*)+1 from FROM employees e2
inner join departments d2 on e2.departmentID = d2.departmentID
where d2.name < d.name
or (d2.name = d.name and e2.employeeID < e2.employeeID) -- tie breaker
) as rownum
FROM employees e
INNER JOIN Departments D ON
e.DepartmentID = d.DepartmentID
WHERE rownum between @startRowIndex and (@startRowIndex + @maximumRows - 1)
ORDER BY d.Name, e.employeeID
Note the essence of the solution comes from how rownum is generated by the inner select. Once you 'get' the idea, you can make the inner select order asc or desc by any column or columns you like, provided you use the unique key to break any ties.
good luck
--dQmQ