Is there any simple way to implement pagination in sybase? In postgres there are limit and offset in mysql there is limit X,Y. What about sybase? There is top clausure to li
You could try using the set ROWCOUNT twice like this:
declare @skipRows int, @getRows int SELECT @skipRows=50 SELECT @getRows=10 set ROWCOUNT @skipRows SELECT caslsource_id into #caslsource_paging FROM caslsources set rowcount @getRows Select * from caslsources where caslsource_id not in (select caslsource_id from #caslsource_paging) DROP TABLE #caslsource_paging
This creates a temporary table of rows to skip. You will need to add your WHERE and ORER BY clauses to both the SELECTs to skip the right pages.
I don't know if this is ASE or a different product but the following pattern works across several databases I've worked with as long as there is a way to produce a temp table with a row number somehow and you can identify a unique key for each row:
Input parameters:
declare @p_first int /* max number of rows to see; may be null (= all results); otherwise must be positive number */
declare @p_skipFirst int /* number of rows to skip before the results; must be nonnegative number */
declare @p_after PKTYPE /* key for the row before you start skipping; may be null */
given a table:
RowNumber | RowIndex | DataCol1
1 | 1234 | Joe
2 | 1235 | Sue
3 | 2000 | John
4 | 2005 | Frank
5 | 3000 | Tom
6 | 4000 | Alice
the parameter set:
set @p_first = 5
set @p_skipFirst = 2
set @p_after = 1235
would represent rows 5 and 6.
An additional set of parameters can represent paging from the end of the table in reverse:
declare @p_last int /* max number of rows to see; may be null (= all results); otherwise must be positive number */
declare @p_skipLast int /* number of rows to skip after the results; must be nonnegative number */
declare @p_before PKTYPE /* key for the row after you start skipping; may be null */
Assuming your unsorted table is in #resultsBeforeSort
with an index column named RowIndex
you can sort this with the following script:
select RowNumber = identity(10), *
into #results
from #resultsBeforeSort
/*
you might also wish to have a where clause on this query
this sort is dynamically generated based on a sort expression and
ultimately ended with RowIndex to ensure a deterministic order
*/
order by Column1, Column2 desc, RowIndex
declare @p_total int, @p_min int, @p_max int
select @p_total = count(*) from #results
select @p_min = case when @p_after is null then 1 + @p_skipFirst else @p_total + 1 end
select @p_min = RowNumber + @p_skipFirst from #results where [RowIndex] = @p_after
select @p_max = case when @p_before is null then @p_total - @p_skipLast else 0 end
select @p_max = RowNumber - @p_skipLast from #results where [RowIndex] = @p_before
declare @p_min2 int, @p_max2 int
set @p_min2 = @p_min
set @p_max2 = @p_max
select @p_max2 = case when @p_first is null then @p_max else @p_min + @p_first - 1 end
select @p_min2 = case when @p_last is null then @p_min else @p_max - @p_last end
select @p_min = case when @p_min2 > @p_min then @p_min2 else @p_min end
select @p_max = case when @p_max2 < @p_max then @p_max2 else @p_max end
that script sets up the parameters @p_min
, @p_max
, and @p_total
as well as the temp table #results
You can then use this to select actual data; select 2 table results, first one being metadata (select this first because the second table might not have any actual rows and your reader implementation might not be capable of dealing with that without backtracking):
select [Count] = @p_total,
HasPreviousPage = (case when @p_min > 1 then 1 else 0 end),
HasNextPage = (case when @p_max + 1 < @p_total then 1 else 0 end)
followed by the paged window of results that you actually want:
select [RowIndex], Col1, Col2, Col3
from #results where RowNumber between @p_min and @p_max
Doing this generic solution permits the ability to expose whatever paging strategy you wish. You can do a streaming solution (facebook, google, stackoverflow, reddit, ...) via @p_after
and @p_first
(or @p_before
and @p_last
). You can do an offset + take with @p_first
and @p_skipFirst
. You can also do a page + size with the same parameters @p_first = size
and @p_skipFirst = (page - 1) * size
. Further you can do more esoteric paging strategies (last X pages, between absolute records, offset + anchor, etc) with other combinations of parameters.
This said, Sybase (SAP) ASE does now directly support the offset + take strategy via rows limit @p_first offset @p_skipFirst
. If you only wished to support that strategy you could simplify the above to:
declare @p_total int
select @p_total = count(*) from #resultsBeforeSort
select [Count] = @p_total,
[HasPreviousPage] = (case when @p_skipFirst > 0 then 1 else 0 end),
[HasNextPage] = (case when @p_total > @p_skipFirst + @p_first then 1 else 0 end)
select [RowIndex], Col1, Col2, Col3
from #resultsBeforeSort
order by Column1, Column2 desc, RowIndex
rows limit @p_first offset @p_skipFirst
Quoting from http://www.isug.com/Sybase_FAQ/ASE/section6.2.html#6.2.12:
Sybase does not have a direct equivalent to Oracle's rownum but its functionality can be emulated in a lot of cases.
You can set a maximum rowcount
, which will limit the number of rows returned by any particular query:
set rowcount 150
That limit will apply until it is reset:
set rowcount 0
You could select into a temporary table, then pull data from that:
set rowcount 150
select pseudo_key = identity(3),
col1,
col2
into #tempA
from masterTable
where clause...
order by 2,3
select col1,col2 from #tempA where pseudo_key between 100 and 150
You could optimize storage on the temp table by storing only ID columns, which you then join back to the original table for your select.
The FAQ also suggests other solutions, including cursors or Sybperl.
Sybase SQL Anywhere example, rows per page:10, offset:1000.
SELECT top 10 start at 1001 * FROM employee order by employeeid
Note: You need to specify the order by
column.
// First row = 1000
// Last row = 1009
// Total row = 1009 - 1000 + 1 = 10
// Restriction: exec sp_dboption 'DATABASE_NAME','select into/bulkcopy','true'
select TOP 1009 *, rownum=identity(10)
into #people
from people
where upper(surname) like 'B%'
select * from #people where rownum >= 1000
drop table #people
// It shoulde be better SQL-ANSI-2008 (but we have to wait):
// SELECT * FROM people
// where upper(surname) like 'B%'
// OFFSET 1000 ROWS FETCH NEXT 10 ROWS ONLY
I'm very late to the party but I've happened to stumble on this problem and found a better answer using TOP and START AT from sybase doc. You need to use ORDER BY for or you will have unpredictable results.
http://dcx.sybase.com/1101/en/dbusage_en11/first-order-formatting.html
SELECT TOP 2 START AT 5 * FROM Employees ORDER BY Surname DESC;