Sybase 分页偏移量

发布于 2024-12-09 14:17:02 字数 143 浏览 0 评论 0原文

sybase有没有简单的实现分页的方法? 在postgres中有限制和偏移量,在mysql中有限制X,Y。西贝斯呢?有顶部子句来限制结果,但为了实现完整分页,还需要偏移。 如果有几个页面,这不是问题,我可以简单地在客户端修剪结果,但如果有数百万行,我只想获取我需要的数据。

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 limit results but to achieve full pagination there is also offset needed.
It is not a problem if there are a few pags, I can simply trim results on the client side, but if there are millions of rows I would like to fetch only data that I need.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

诗化ㄋ丶相逢 2024-12-16 14:17:02
// 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
// 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
红墙和绿瓦 2024-12-16 14:17:02

我参加聚会很晚了,但我碰巧偶然发现了这个问题,并使用 sybase 文档中的 TOP 和 START AT 找到了更好的答案。您需要使用 ORDER BY ,否则您将得到不可预测的结果。

http://dcx.sybase.com/1101/en/ dbusage_en11/first-order-formatting.html

选择前 2 个从 5 开始 *
来自员工
按姓氏 DESC 排序;

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;

酒中人 2024-12-16 14:17:02

引用自 http://www.isug.com/Sybase_FAQ/ASE /section6.2.html#6.2.12

Sybase 没有直接相当于 Oracle 的 rownum,但在很多情况下可以模拟其功能。

您可以设置最大行数,这将限制任何特定查询返回的行数:

set rowcount 150

该限制将一直适用,直到重置为止:

set rowcount 0

您可以选择临时表,然后从中提取数据:

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

您可以通过仅存储 ID 列来优化临时表上的存储,然后将这些列连接回原始表以供选择。

FAQ 还建议了其他解决方案,包括游标或 Sybperl。

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.

森林很绿却致人迷途 2024-12-16 14:17:02

Sybase SQL Anywhere 示例,每页行数:10,偏移量:1000。

SELECT top 10 start at 1001  * FROM employee order by employeeid

注意:您需要指定 order by 列。

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.

恬淡成诗 2024-12-16 14:17:02

不幸的是,Sybase 不提供设置起始和偏移限制的功能。最好的方法是使用 SET ROWCOUNT 来限制返回的记录数。如果您有 1,000 条记录并想要按 50 个条目分页,那么类似的操作将返回第一页...

set rowcount 50
select * from orders

对于第二页......

set rowcount 100
select * from orders

然后您可以选择不在 Java 中显示前 50 条记录代码。显然,当您向前翻页时,您最终不得不返回越来越大的数据集。您关于如何处理 1,000,000 条记录的问题对于分页的用户界面似乎不切实际。没有用户在 Google 上搜索后会向前翻页 1,000 次来寻找内容。

如果我有自然键怎么办?

如果您确实有一个相对较大的数据集,并且可以在数据上使用自然键,这将有助于限制返回的记录。例如,如果您有一个联系人列表,并且有一个界面,允许您的用户选择 A 到 Z 来根据姓氏对目录中的人员进行寻呼,那么您可以执行以下操作

set rowcount 50
select * from people 
where upper(surname) like 'B%'

:姓氏以“B”开头,您使用与上面相同的方法向前翻页……

set rowcount 100
select * from people 
where upper(surname) like 'B%'

并删除 Java 代码中的前 50 个。

在此示例之后,也许您可​​以按日期或对用户需求有意义的其他一些数据来限制搜索。

希望这有帮助!

Unfortunately Sybase does not provide the ability to set a start and offset limit. The best you can achieve is to use the SET ROWCOUNT to limit the number of records returned. If you have 1,000 records and want to page by 50 entries then something like this will bring back the first page...

set rowcount 50
select * from orders

For the second page...

set rowcount 100
select * from orders

...and then you can choose not to display the first 50 from within your Java code. Obviously as you page forward you end up having to return larger and larger data sets. Your question about what to do with 1,000,000 records doesn't seem practical for a user interface that is paginated. No user searches on Google and then pages forward 1,000 times looking for stuff.

What if I have a Natural Key?

If you do have a relatively large data set and you can use a natural key on your data, this will help limit the records returned. For example if you have a list of contacts and have an interface that allows your users to select A to Z to page the people in the directory based on Surname then you can do something like...

set rowcount 50
select * from people 
where upper(surname) like 'B%'

When there are more than 50 people with a surname starting with 'B' you use the same approach as above to page forward...

set rowcount 100
select * from people 
where upper(surname) like 'B%'

... and remove the first 50 in Java code.

Following on from this example, maybe you can limit searches by date, or some other piece of data meaningful to your users requriements.

Hope this helps!

絕版丫頭 2024-12-16 14:17:02

您可以尝试使用 set ROWCOUNT 两次,如下所示:

    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

这将创建一个要跳过的行的临时表。您需要将 WHERE 和 ORER BY 子句添加到两个 SELECT 中以跳过正确的页面。

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.

他夏了夏天 2024-12-16 14:17:02

我不知道这是 ASE 还是不同的产品,但只要有办法以某种方式生成带有行号的临时表并且您可以识别唯一键,以下模式就适用于我使用过的多个数据库对于每一行:

输入参数:

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 */

给定一个表:

RowNumber | RowIndex | DataCol1
1         | 1234     | Joe
2         | 1235     | Sue
3         | 2000     | John
4         | 2005     | Frank
5         | 3000     | Tom
6         | 4000     | Alice

参数集:

set @p_first = 5
set @p_skipFirst = 2
set @p_after = 1235

将表示第 5 行和第 6 行。

一组附加参数可以表示从表末尾反向分页:

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 */

假设未排序的表位于#resultsBeforeSort 具有名为 RowIndex 的索引列,您可以使用以下脚本对其进行排序:

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

该脚本设置参数 @p_min, @p_max@p_total 以及临时表 #results

然后您可以使用它来选择实际数据;选择 2 个表结果,第一个是元数据(首先选择此表,因为第二个表可能没有任何实际行,并且您的阅读器实现可能无法在不回溯的情况下处理该行):

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)

后面是您实际想要的结果的分页窗口:

select [RowIndex], Col1, Col2, Col3 
from #results where RowNumber between @p_min and @p_max

执行此通用解决方案允许公开您想要的任何分页策略。您可以通过 @p_after@p_first (或 @p_before和@p_last)。您可以使用 @p_first@p_skipFirst 进行偏移+拍摄。您还可以使用相同的参数 @p_first = size@p_skipFirst = (page - 1) * size 执行 page + size。此外,您可以使用其他参数组合执行更多深奥的分页策略(最后 X 页、绝对记录之间、偏移+锚点等)。


也就是说,Sybase (SAP) ASE 现在通过rows limit @p_first offset @p_skipFirst 直接支持 offset + take 策略。如果您只想支持该策略,您可以将上述简化为:

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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文