最大的网站源码资源下载站,
方法一:select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段
10 = 每页记录数
20 = (当前页 + 1) * 每页记录数
以上语句即可以实现分页,但是最后取出的结果排序是升序,如果需要结果集为降序(例如时间),则有两种方法可以处理
1.使用以下语句,但效率可能要降低一些
select * from 表名 b, (select top 10 主键字段,排序字段 from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a order by 排序字段 ) c where b.主键字段 = c.主键字段 order by c.排序字段 desc
2.在ado里处理,将记录集游标移到最后,然后前移
''以下为asp范例
set rstemp = server.createobject("adodb.recordset")
rstemp.open 语句,conn,1,1
rstemp.movelast
for i = 1 to rstemp.recordcount
'取值....
rstemp.moveprevious
next
经测试,以上分页方法比使用临时表分页速度还要快,并且简单易用.
方法二:
大数据量下的分页
对于非常大的数据模型而言,分页检索时,每次都加载整个数据源非常浪费。通常的选择是检索页面大小的块区的数据,而非检索所有的数据,然后单步执行当前行。
本文演示asp.net的datagrid和sql server 实现大数据量下的分页,为了便于实现演示,数据表采用了northwind数据库的orders表(830条记录)。
如果数据表中有唯一的自增索引,并且这个字段没有出现断号现象。检索页面大小的块区数据就非常简单了。通过简单的sql语句就可以实现这个功能:
select * from orders where orderid between 10248 and 10253 |
其中,开始编号为:(currentpageindex - 1) * pagesize 结束编号为:currentpageindex * pagesize
当然,如果这个字段断号不是很严重,而且允许不是很严格的按照每页条数分页,这样的方法也是可以用的。
如果这个字段断号,或者需要按照其他条件排序分页,就要复杂些了。首先要获得这个页面需要显示的编号,然后再按照这个编号获得需要的块区数据。根据编号获得块区数据很简单。不过用下面方式获得数据排序并不是按照指定的id列表顺序,这时候还要附加order by 命令。
select * from orders where orderid in (10248,10249,10250,10251,10252,10253) order by orderid desc |
获得这个页面需要显示的编号列表就复杂多了,而且有多种方案:
方案一:维护一个表,这个表记录需要显示的这些编号排序顺序。(这个表可以是临时表,也可以是物理表)。下面演示了利用一个全局临时表。这个全局临时表记录需要显示的编号。注意排序,这里的order by 就是需要显示的排序顺序。
create table ##temptable(iid int identity (1, 1) not null,mainid int not null)insert ##temptable(mainid) select orderid from orders order by orderid descselect * from ##temptabledrop table ##temptable -- 实际执行时候,删除全部临时表当然不再这里执行。 |
这个临时表存在,获得指定分页的分块数据就很简单了。看下面代码:
create table ##temptable(iid int identity (1, 1) not null,mainid int not null)insert ##temptable(mainid) select orderid from orders order by orderid descdeclare @pagesize int,@currpage int,@strsql varchar(2000),@idstr varchar(1000)select @pagesize = 30select @currpage = 2select @idstr = ''select @idstr = @idstr + ltrim(rtrim(str(mainid))) + ',' from ##temptable where iid between ((@currpage-1)*@pagesize+1) and @currpage*@pagesizeif @idstr <> '' begin select @idstr = left(@idstr,len(@idstr)-1)endselect @strsql = 'select * from orders where orderid in ('[email protected]+') order by orderid desc 'exec(@strsql)drop table ##temptable |
注意:实际使用这个方案的时候,还要考虑何时更新这个全局临时表,一般是放到计划任务中,定时更新这个汇总表。
方案二:每次都去查询,每次获得最新的编号顺序。由于这时候不存在这个临时表,书写获得需要显示页面的编号的字符串就需要点技巧,看下面的代码:asp.net 的 datagrid 提供了使用这种分区的数据的方法。 datagrid 通过 allowcustompaging 和 virtualitemcount 属性支持块区操作。如果 allowcustompaging 为 true,则 datagrid 不会根据 currentpageindex 计算数据模型中的起始显示位置。datagrid 将显示数据模型中的所有数据,而页导航栏将当前位置报告为 (virtualitemcount+pagesize-1)/pagesize 之 currentpageindex 页。下面的示例说明此功能。
declare @pagesize int,@currpage int,@topnum int,@previous intselect @pagesize = 30select @currpage = 2select @topnum = @currpage * @pagesizeselect @previous = (@currpage - 1) * @pagesizedeclare @i int,@idstr nvarchar(500),@strsql nvarchar(1000)select @i = 0select @strsql = n''select @strsql = @strsql + n' select top '+str(@topnum)+ ' @i = @i + 1 'select @strsql = @strsql + n', @idstr = 'select @strsql = @strsql + n'case when @i > '+str(@previous)+' then @idstr + ltrim(rtrim(str(orderid))) + '','' 'select @strsql = @strsql + n'else n''''end 'select @strsql = @strsql + n'from orders 'select @strsql = ltrim(rtrim(@strsql)) + n' order by orderid desc 'select @idstr = n''exec sp_executesql @strsql,n'@i int,@idstr varchar(500) output',@i,@idstr outputif len(rtrim(ltrim(@idstr))) > 0begin select @idstr = left(@idstr,len(@idstr)-1)endselect @strsql = 'select * from orders where orderid in ('[email protected]+')'exec(@strsql) |
protected void binddatagrid(int currpage) { string strconn = "data source=(local);integrated security=sspi;database=northwind"; // 请确认 机器名/aspnet 用户可以访问northwind数据库 sqlcommand cmd = new sqlcommand(); sqlconnection conn = new sqlconnection(strconn); sqlparameter[] parms = new sqlparameter[] { new sqlparameter("@pagesize",sqldbtype.int), new sqlparameter("@currpage",sqldbtype.int), new sqlparameter("@searchsql",sqldbtype.nvarchar,128), new sqlparameter("@count",sqldbtype.int), }; parms[0].value = datagrid1.pagesize; parms[1].value = (currpage+1); // 数据库的分页算法第一页是1 datagrid的第一页是0 parms[2].value = dbnull.value; parms[3].direction = parameterdirection.output; parms[3].value = dbnull.value; dataset ds = new dataset(); try { if (conn.state != connectionstate.open) conn.open(); cmd.connection = conn; cmd.commandtext = "selected_page_list"; cmd.commandtype = commandtype.storedprocedure; if (parms != null) { foreach (sqlparameter parm in parms) cmd.parameters.add(parm); } sqldataadapter da = new sqldataadapter(cmd); da.fill(ds); int aa = convert.toint32(parms[3].value.tostring()); cmd.parameters.clear(); if (currpage == 0) { datagrid1.virtualitemcount = aa; } datagrid1.currentpageindex = currpage; datagrid1.datasource = ds; datagrid1.databind(); } catch(exception ewx) { conn.close(); response.write (ewx.message.tostring()); response.end(); } } void page_load(object sender, eventargs e ) { if (!ispostback) { binddatagrid(0); // 第一次打开这个页面,访问分页的第一页 } } void mydatagrid_page(object sender, datagridpagechangedeventargs e) { binddatagrid(e.newpageindex); } |
如果你有更多数据量的表稍加修改,也可以使用本演示程序。其下是演示代码下载,演示代码使用的是方案二。使用方法看readme.txt文件。
整个演示代码 下载
http://chs.gotdotnet.com/quickstart/aspplus/samples/webforms/ctrlref/webctrl/datagrid/doc_datagrid.aspx#paging
这里演示了利用datagrid 的这个功能(没有本文中讨论的利用存储过程获得分区数据)。如对datagrid的这个功能不太熟悉,请先看这里。
方法三:
虽然 datagrid 控件自己带了一个分页处理机制,但它是将符合查询条件的所有记录读入内存,然后进行分页显示的。随着符合条件的记录数目增多,就会出现运行效率问题,或者至少是资源的利用率下降。
下面的代码示例都以下面的表结构为准:
articles 表 | sql server 类型 | oracle 类型 | |
pk | id | int (自增) | number(9) (插入时在当前最大值上加1) |
author | nvarchar(10) | nvarchar2(10) | |
title | nvarchar(50) | nvarchar2(50) | |
pubtime | datetime | date |
sql server / access 等微软产品中,我们通常的自定义分页有两种思路:
一种是以 asp.net forum 为代表的、“临时表”方法:即在存储过程中建立一个临时表,该临时表包含一个序号字段(1,2,3,....)以及表的主键(其他能够唯一确定一行记录的字段也是可以的)字段。存储过程可能如下:(编号 ss1)
另一种可能更适合程序中“拼凑” sql 语句:用两次 top 命令取得我们所要的分页数据,例如:(编号 ss2)
这个的想法就是“掐头去尾”,还有不少分页的方法,这里就不一一列出了。
对于 oracle 数据库,有几处不同严重妨碍了上面几个方法的实施,比如,oracle 不支持 top 关键字:不过这个好像并不十分严重,因为它提供了 rownum 这个隐式游标,可以实现与 top 类似的功能,如:
要写成
rownum 是记录序号(1,2,3...),但有一个比较麻烦的事情是:如果 sql 语句中有 order by ... 排序的时候,rownum 居然是先“标号”后排序!这样,这个序号如果不加处理是不合乎使用需求的。
至于临时表,oracle 的临时表和 sql server 的有很大不同,我还没搞懂这个东西,就不妄加揣测了。
国内网站中介绍 oracle 分页的资料很少,我找到了一个国外站点(www.faqts.com)的一篇 faq,根据这篇文章的介绍,可以如下分页:(编号 ora1)
其中蓝色部分可以改为任意的、需要的 sql select 语句,这点倒是挺方便的。
方法四:
今天突然发现,oracle原来可以这样实现分页功能:
select * from (select rownum rdd,field1,field2 from t_table where rownum<=400) where rdd>200
上述语句实现了从第201条记录开始处取200条记录
新闻热点
疑难解答