在你的SQL语句里,加一段
order by 价钱
或
order by 面积你分页时要用session变量或加在URL里的办法记住用户的选择
order by 价钱
或
order by 面积你分页时要用session变量或加在URL里的办法记住用户的选择
解决方案 »
- 侧栏左右滑动这样的效果怎么做出来?
- 获得ColumnTree中选中的值
- 在线跪求正则表达式时间yyyy/mm/dd的表示方法
- 如果使打印预览窗口最大化?
- 有没有不用frame分框的树型菜单???
- setTimeout只执行一次,没有定时执行的问题!
- 菜鸟问:这段代码应该怎样修改才合适?
- 关于网页里图片特效 急 在线等 100分马上送出
- 一个关于select里面用了onChange事件的奇怪问题。急切ing....
- [Extjs]TreeGrid相关问题....在线等....
- 44分问一个简单问题,怎样打开一个网页后让其马上自动的刷新一遍?
- ?网页上点击刷新按钮就会显示“警告:该网页已过期!”是怎么实现的?
一. 引言
贵刊今年10月10日东北大学张春明和姜绍飞的"Web数据库记录分页技术与实现"一文介绍了利用微软RecordSet组件对象实现数据库记录分页. 该方法虽然有其可取之处, 但也有不足之处.
首先该方法将所有查询结果保存到一个RecordSet对象中, 然后利用RecordSet对象的几个特殊属性把数据库记录划分成不同的页面. 这样在同一查询Session的不同页面之间, 要么保存该RecordSet对象于Session中, 要么每次都进行查询以得到RecordSet对象. 其缺点是很明显的, 不仅浪费资源, 而且缺乏效率.
该方法的另外一个明显缺点是缺乏可移植性, 如很难移植到J2EE应用中. 因为它过于依赖微软RecordSet组件对象固有的特性以实现分页的目的.
大家知道, WEB应用中数据库连接资源是很昂贵的, 因此, 有必要探索一种有效的记录分页算法,同时兼顾到移植性.
二. 基于SQL分页算法
我们知道, SQL 是一种功能性非常强的数据库编程语言, 同时它也是一个工业标准. 因此, 如果我们能够演绎出一套基于 SQL 的有效分页算法, 那么也就兼顾了算法的可移植性. 本文将要介绍的正是这样一种分页算法.
1. 假设 records_per_page 包含每页记录数
2. 查询总记录数并计算总页数
(1) 查询总记录数 total_records
select count(*) from your-table-list
where your-criteria
(2) 计算总页数 total_pages
total_pages = (total_records + records_per_page - 1)
/ records_per_page
3. 假设 current_page 包含当前页号
则其约束区间为 [1, total_pages]
4. 计算未显示记录数 not_shown_records
not_shown_records = total_records -
(current_page - 1) * records_per_page
5. 查询当前页所有记录
select top records_per_page *
from (
select top not_shown_records *
from your-table-list
where your-criteria
order by your-sort-field desc
) a
order by a.your-sort-field asc
注意: your-sort-field 包含了一个排序字段. 你可以指定
多个排序字段, 但是必须保证里外包含相同的排序字段.
外层的每个排序字段前加上"a."
该算法在同一查询Session中, 只需要查询总记录数并计算总页数一次. 然后, 在不同页面之间传递总记录数和总页数. 每次只查询当前页所需记录. 这样不仅节省了连接资源, 而且效率也高, 同时兼顾了移植性. 你不仅可以在微软ASP中使用该分页算法, 也可以在SUN J2EE平台上轻松实现, 你甚至可以在CGI/PERL中使用该技术.
三. 实现示例
下面的程序示例使用了微软ASP技术和SQL7.0 Northwind数据库中的Orders表来演示如何实现这一分页算法.这是一个完整的经测试过的程序. 由于程序注释很详细, 这里就不再赘述.
<%@ Language=JavaScript%>
<%
//-------------------------------------------------------------
// dbpaging.asp
//-------------------------------------------------------------
Response.Expires = -1;
// 定义变量
var nRecordsPerPage, nTotalRecords, nTotalPages, nCurrentPage, nNotShownRecords;
var nFirstPage, nPrevPage, nNextPage, nLastPage;
var szConnection, oConnection, oRecordset, szSql;
var szShowPageUrl;
// 查询同一查询Session不同页面之间传递参数
nTotalRecords = parseInt(Request.QueryString("totalrecords"));
nTotalPages = parseInt(Request.QueryString("totalpages"));
nCurrentPage = parseInt(Request.QueryString("showpage"));
// 设置每页显示记录数
nRecordsPerPage = 10;
// ODBC连接参数: 使用你自己的DSN,帐号以及密码
// 这里Northwind应指向微软SQL7.0 Northwind示例数据库
szConnection = "DSN=Northwind;UID=test;PWD=;";
oConnection = Server.CreateObject("ADODB.Connection");
oConnection.Open(szConnection);
// 检测是否首次进入该查询Session
if (isNaN(nCurrentPage)) {
// 是, 设置第一页为当前页, 查询总记录数并计算总页数
nCurrentPage = 1;
szSql = "select count(*) from Orders";
oRecordset = oConnection.Execute(szSql);
nTotalRecords = oRecordset(0).value;
oRecordset.Close();
oRecordset = null;
nTotalPages = parseInt((nTotalRecords + nRecordsPerPage - 1) / nRecordsPerPage);
}
// 设置页面切换参数
nFirstPage = 1; // 首页
nPrevPage = nCurrentPage - 1; // 前一页
nNextPage = nCurrentPage + 1; // 下一页
nLastPage = nTotalPages; // 最后页
if (nPrevPage < 1) nPrevPage = 0;
if (nNextPage > nTotalPages) nNextPage = 0;
// 计算未显示记录数
nNotShownRecords = nTotalRecords - (nCurrentPage - 1) * nRecordsPerPage;
// 查询当前页所有记录
szSql = "select top " + nRecordsPerPage + " * " +
"from ( " +
"select top " + nNotShownRecords + " OrderID, CustomerID, " +
"ShipName, ShipAddress, ShipCity, ShipPostalCode, ShipCountry " +
"from Orders " +
"order by OrderID desc " +
") a " +
"order by a.OrderID asc";
oRecordset = oConnection.Execute(szSql);
%>
<html><head><title>DB Paging Demo</title></head><body><center>
<%
// 显示当前页所有记录
if (!oRecordset.EOF) {
%><table cellpadding="2" cellspacing="0" border="1" width="800"><tr>
<td align="center"><b>Order ID</b></td>
<td align="center"><b>Customer ID</b></td>
<td align="center"><b>Ship Name</b></td>
<td align="center"><b>Ship Address</b></td>
<td align="center"><b>Ship City</b></td>
<td align="center"><b>Ship Postal Code</b></td>
<td align="center"><b>Ship Country</b></td>
</tr>
<%
oRecordset.MoveFirst();
while(!oRecordset.EOF) {
%><tr>
<td align="center"><%=oRecordset("OrderID").value%></td>
<td align="left"><%=oRecordset("CustomerID").value%></td>
<td align="left"><%=oRecordset("ShipName").value%></td>
<td align="left"><%=oRecordset("ShipAddress").value%></td>
<td align="left"><%=oRecordset("ShipCity").value%></td>
<td align="left"><%=oRecordset("ShipPostalCode").value%></td>
<td align="left"><%=oRecordset("ShipCountry").value%></td>
</tr>
<%
oRecordset.MoveNext();
}
%></table><%
}
oRecordset.Close();
oRecordset = null;
// 设置页面切换链接参数
szShowPageUrl = "dbpaging.asp?totalrecords=" + nTotalRecords
+ "&totalpages=" + nTotalPages + "&showpage=";
%><table cellpadding="2" cellspacing="0" border="0" width="600"><tr>
<td align="center"> </td>
<td align="center"> <b><%
// 显示首页链接
if (nPrevPage > 0) {
%><p><a href="<%=szShowPageUrl%><%=nFirstPage%>">First</a><%
}
%></b></td>
<td align="center"> <b><%
// 显示前一页链接
if (nPrevPage > 0) {
%><p><a href="<%=szShowPageUrl%><%=nPrevPage%>">Previous</a><%
}
%></b></td>
<td align="center"> </td>
<td align="center"> <b><%
// 显示下一页链接
if (nNextPage > 0 ) {
%><p><a href="<%=szShowPageUrl%><%=nNextPage%>">Next</a><%
}
%></b></td>
<td align="center"> <b><%
// 显示最后页链接
if (nNextPage > 0 ) {
%><p><a href="<%=szShowPageUrl%><%=nLastPage%>">Last</a><%
}
%></b></td>
<td align="center"> </td>
</tr></table>
</center></body></html>
四. 结论
由于WEB应用本身的局限性以及平台的多样性, 这就要求我们在后台处理时应当对技术和算法进行慎重考虑, 不仅要考虑其可实现性, 而且更应该注意其效率和可移植性. 对于WEB应用来讲数据库记录分页是一个常见的要求, 本文给出了一个常用的基于SQL的行之有效的分页算法. 不足之处, 恭请方家指正.
1.上述,写在Session对象的思路虽然可以节省些资源,但是即时性就要受到影响。如果有用户对数据库进行大的修改,则不能保证程序正确。这个对于Web程序好像问题不大,但最好能够让这个Session对象定时更新
2.上述查询总记录数 total_records 的方法也有待改进。
select count(*) from your-table-list where your-criteria
通常一个页面显示的数据都是一个复杂的查询结果;使用count(*)似乎不能简单的描述,如何改进呢?