Reputation:
Im trying to page results in ms sql server and I'm having some troubles getting the right result. I'd like to achieve the same result as mysql:s LIMIT and Iäm trying to use this model to do it:
SELECT * FROM (
SELECT TOP x * FROM (
SELECT TOP y fields
FROM table
WHERE conditions
ORDER BY table.field ASC) as foo
ORDER by field DESC) as bar
ORDER by field ASC
from: http://josephlindsay.com/archives/2005/05/27/paging-results-in-ms-sql-server/
The original query listing top 30 rows is the following:
SELECT TOP 30 pt.[BSNR], t.ID, pt.RESDATUMTID, pt.LAND1, pt.HPL1, pt.ANKDATUMTID, pt.LAND2, pt.HPL2
FROM [statistik2].[dbo].[ttrip] AS t
JOIN [statistik2].[dbo].[tparttrip] AS pt
ON t.ID = pt.TRIP_ID
WHERE t.DBKRDAT > '2012-06-27'
ORDER BY pt.BSNR DESC, t.ID, pt.RESDATUMTID
And my attempt is:
SELECT * FROM (
SELECT TOP 10 * FROM (
SELECT TOP 30 pt.ID AS PTID, pt.[BSNR], t.ID, pt.RESDATUMTID, pt.LAND1, pt.HPL1, pt.ANKDATUMTID, pt.LAND2, pt.HPL2
FROM [statistik2].[dbo].[ttrip] AS t
JOIN [statistik2].[dbo].[tparttrip] AS pt
ON t.ID = pt.TRIP_ID
WHERE t.DBKRDAT > '2012-06-27'
ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID
) as pttt
ORDER BY pttt.PTID DESC) AS ptttt
ORDER BY ptttt.PTID
Output from the queries: http://speedy.sh/5NQeq/sqloutput.txt
Can someone explain what I'm doing wrong?
Upvotes: 1
Views: 141
Reputation: 14012
You can use ROW_NUMBER() to get a running count - this makes paging a lot easier...e.g.
(Note: this is for SQL 2005 and above - SQL 2000 doesn't support the row_number() function)
Assuming a table that has one column 'Name':
SELECT * FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY Name) as RunningVal, * FROM Names
) as Running
WHERE RunningVal BETWEEN 5 AND 10
The whole triple-sort thing is a bit old school to be honest :P
In your case it would be something like:
SELECT * FROM (
SELECT TOP 30
ROW_NUMBER() OVER (ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID) as RunningVal,
pt.ID AS PTID,
pt.[BSNR],
t.ID,
pt.RESDATUMTID,
pt.LAND1,
pt.HPL1,
pt.ANKDATUMTID,
pt.LAND2,
pt.HPL2
FROM [statistik2].[dbo].[ttrip] AS t
JOIN [statistik2].[dbo].[tparttrip] AS pt
ON t.ID = pt.TRIP_ID
WHERE t.DBKRDAT > '2012-06-27'
ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID
) as Running
WHERE RunningVal BETWEEN 1 AND 10
In fact you can even get rid of the inner TOP and just use:
SELECT * FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID) as RunningVal,
pt.ID AS PTID,
pt.[BSNR],
t.ID,
pt.RESDATUMTID,
pt.LAND1,
pt.HPL1,
pt.ANKDATUMTID,
pt.LAND2,
pt.HPL2
FROM [statistik2].[dbo].[ttrip] AS t
JOIN [statistik2].[dbo].[tparttrip] AS pt
ON t.ID = pt.TRIP_ID
WHERE t.DBKRDAT > '2012-06-27'
ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID
) as Running
WHERE RunningVal BETWEEN @x AND @y
Where @x is the lower limit, and @y is the upper (BETWEEN is inclusive and ROW_NUMBER() starts at 1 so x = 1 and y = 10 will give you records 1-10)
Edit: Not sure what happens in MySql when you specify an OFFSET in LIMIT that is out of range (and the official docs don't seem to mention this one as far as I can see), but just be cautious that if you specify @x = 100 and @y = 110 and there are only 50 records in the table, you will get no results
Edit2: Added a SQL fiddle link if you want to fiddle it!
http://sqlfiddle.com/#!3/57808/3
Upvotes: 2
Reputation: 77657
Pay attention to the sample query.
The innermost subquery orders the results by field ASC
. That is the main order through all the pages. The innermost subquery takes the top y
rows in that order.
The middle-tier subquery reverses the order and takes the top x
rows from the previous result, thus effectively taking the bottom x
rows of the top y
rows of the entire dataset.
The main query merely re-establishes the main order of rows.
You should do just the same. Your innermost query orders rows like this:
ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID
If that is your main row order, then you should use the reversed version of it in your middle-tier subquery, i.e. like this:
ORDER BY pt.BSNR ASC, t.ID ASC, pt.RESDATUMTID DESC
It may not be that important how you order rows in your main query, but I would follow the sample and reversed the order again, making it match that of the innermost query.
Upvotes: 1