Colorful Life2010

Sybase 分页方法,存储过程(转)
Weather:17~27度,晴,北风4~5级

您可以使用 FIRST 或 TOP 关键字限制查询的结果集中包括的行数。这些关键字用于包括 ORDER BY 子句的查询。

示例  
以下查询返回在按姓氏对雇员进行排序时首先出现的雇员的信息:

SELECT FIRST *
FROM employee
ORDER BY emp_lname
以下查询返回按姓氏排序时出现的前五个雇员:

SELECT TOP 5 *
FROM employee
ORDER BY emp_lname
在使用 TOP 时,您也可以使用 START AT 来提供偏移。以下语句列出按姓氏以降序进行排序时出现的第五个和第六个雇员:

SELECT TOP 2 START AT 5 *
FROM employee
ORDER BY emp_lname DESC
FIRST 和 TOP 只能与 ORDER BY 子句联合使用,以确保获得一致的结果。如果使用 FIRST 或 TOP 时没有 ORDER BY,则会触发语法警告,并且很可能产生无法预知的结果。

注意  
'start at' 值必须大于 0。当 'top' 为常量时,其值必须大于 0;当 'top' 为变量时,其值必须大于或等于 0。

 

一段很好的分页程序,速度很快,sybase内部员工写的,改成自己需要的SQL吧。

create procedure test_p @ipage int, @num int as    /* @ipage   页码, @num 每页的记录数 */
begin
declare @maxpages int, @rcount int    /* @maxpages 最大页码 */
if @ipage>=100
select @maxpages=ceiling(count(*)/@num) from test
else
          select @maxpages=100000
if @ipage<[email protected]/2  
begin
select @[email protected]*@num
set rowcount @rcount
select id=identity(12),name,descs,ddd into #temptable1 from test order by id
select * from #temptable1   where id>=(@ipage-1)*@num and id<= @ipage*@num
end else
begin
select @rcount=(@[email protected]+1)*@num
set rowcount @rcount
select id=identity(12),name,descs,ddd into #temptable2 from test order by id desc  
select id,name, ddd,descs from #temptable2   where id>=(@[email protected])*@num and id<= (@[email protected]+1)*@num   order by id   desc
end
end

 

 

好事做到底,送个通用版吧

create procedure splitpage @qry varchar(16384),@ipage int, @num int as    /*@qry SQL语句, @ipage 页数, @num 每页记录条数 */
begin
         declare @maxpages int
         declare @rcount int
         declare @execsql varchar(16384)

         if @ipage>=100
                 select @maxpages=ceiling(count(*)/@num) from test
         else
                 select @maxpages=100000
         if @ipage<[email protected]/2
         begin
                 select @[email protected]*@num
                 set rowcount @rcount
                 set @execsql = stuff(@qry,charindex('select',@qry),6,'select sybid=identity(12),')
                 set @execsql = stuff(@execsql, charindex('from',@execsql),4,'into #temptable1 from')
                 set @execsql = @execsql || ' select * from #temptable1   where sybid>' || convert(varchar,(@ipage-1)*@num) || ' and sybid <= ' || convert(varchar,@ipage*@num)
                 execute (@execsql)

         end else
         begin
                 select @rcount=(@[email protected]+1)*@num
                 set rowcount @rcount
                 set @execsql = stuff(@qry,charindex('select',@qry),6,'select sybid=identity(12),')
                 set @execsql = stuff(@execsql, charindex('from',@execsql),4,'into #temptable1 from')
                 set @execsql = @execsql || ' order by sybid desc'
                 set @execsql = @execsql || ' select * from #temptable1 where sybid > ' || convert(varchar,(@[email protected])*@num) || ' and sybid <= ' || convert(varchar,(@[email protected]+1)*@num)
                 execute (@execsql)
         end
end
 

 

 

 

vc00, sybase中的临时表当用select into #table的形式时,是不记录日志的。速度非常快。
这点和oracle不同。算是sybase的一个feature.

ncowboy ,老程序在处理10万页以上结果集会出现问题。用select @maxpages=ceiling(count(*)/@num) from test此处使用是不对的。
由于即席查询时获取maxpages效率不高,对此作以下修改:可以由用户指定最大查询页数,缺省定为5000

create procedure splitpage @qry varchar(16384),@ipage int, @num int,@maxpages int = 5000 as   
/*@qry SQL语句, @ipage 页数, @num 每页记录条数, @maxpages 最大查询页数 */
begin
  
         declare @rcount int
         declare @execsql varchar(16384)

         if @ipage > @maxpages
         begin
       select '输入页数[' || convert(varchar,@ipage) || ']大于最大查询页数[' ||   convert (varchar,@maxpages) ||']'  
               return
         end

         select @[email protected]*@num
         set rowcount @rcount
         set @execsql = stuff(@qry,charindex('select',@qry),6,'select sybid=identity(12),')
         set @execsql = stuff(@execsql, charindex('from',@execsql),4,'into #temptable1 from')
         set @execsql = @execsql || ' select * from #temptable1   where sybid>' || convert(varchar,(@ipage-1)*@num) || ' and sybid <= ' || convert(varchar,@ipage*@num)
         execute (@execsql)
end

由于无法精确且高效取出即席查询结果集的总页数,原程序中考虑后几页查询的优化算法就无法使用了。
如果可以先算出精确的总页数,然后作为参数传给splitpage,那么也可以把查询后几页的算法再补上。

谁有更好的办法也可以提出来大家一起把这个分页存储过程优化到底。
 

 

 

版本更新:1.0.2
注意程序最后要加上set rowcount 0

create procedure splitpage @qry varchar(16384),@ipage int, @num int,@maxpages int = 5000 as   
/*@qry SQL语句, @ipage 页数, @num 每页记录条数, @maxpages 最大查询页数 */
begin 

         declare @rcount int
         declare @execsql varchar(16384)

         if @ipage > @maxpages
         begin
               select '输入页数[' || convert(varchar,@ipage) || ']大于最大查询页数[' ||   convert (varchar,@maxpages) ||']'  
               return
         end

         select @[email protected]*@num
         set rowcount @rcount
         set @execsql = stuff(@qry,charindex('select',@qry),6,'select sybid=identity(12),')
         set @execsql = stuff(@execsql, charindex('from',@execsql),4,'into #temptable1 from')
         set @execsql = @execsql || ' select * from #temptable1   where sybid>' || convert(varchar,(@ipage-1)*@num) || ' and sybid <= ' || convert(varchar,@ipage*@num)
         execute (@execsql)
         set rowcount 0
end
 

历史上的今天: [2005/05/26]真实版:N对夫妻同样问题的老公回答

[Sybase 分页方法,存储过程(转)]的回复

Post a Comment~