Sybase采用固定表+存储过程实现分页
众所周知,sybase没有mysql的limit关键字,也不支持sqlserver的 ROW_NUMBER() 来对查询行数据动态设置ID来帮助索引分页。
网上大部分流传的都是使用临时表,网上搜一搜就可以搜到相关例子,没有用过,言称是很通用。
为了实现简单快速的分页,自己写了一套分页的工具。没有使用临时表,而使用了一个固定表的原因是:
1. 临时表管理上比较麻烦,需要分配表管理的权限,并且临时表一般会放在master库下,如果查询数据很大或者临时表创建drop频繁,对系统性能会有影响。
2.之前的经验认识到,其实大表如果是只写和查,没有数据合并或复杂的联表运算,在索引合理的情况下,速度还是非常好的。这是在我之前做大数据统计时得到的经验。
下面开始建表:
其中id为int型的索引,数据分页就靠他来算。id1和id2一个是int型,一个是varchar型,
CREATE TABLE mytemptable (
id integer NOT NULL,
id1 integer NULL,
id2 varchar(32) NULL
)
ALTER TABLE mytemptable ADD CONSTRAINT pk_orderform PRIMARY KEY (id)
存储过程:
其中type是类型
countsql是分页计算的sql ,比如 select tableid as id from table1 ,其中as id 是必须的
countordersql是分页时的order语句,因为sybase不支持在子查询里加排序,因此只能放在这个里面拼串
sql是真正的查询显示的sql,比如 select tableid as id,name,createdate from table1,其中as id仍旧是必须的
pagesize和currentpage分别是页大小和当前页
CREATE PROCEDURE pageUtil
@type integer ,
@countsql varchar(2048) ,
@countordersql varchar(256) ,
@sql varchar(16284) ,
@pagesize integer ,
@currentpage integer
AS
BEGIN TRAN
DECLARE @minid int
DECLARE @beginid varchar(20)
DECLARE @endid varchar(20)
DECLARE @total int
IF (@type=1)
BEGIN
set @countsql="insert mytemptable(id1,id2) select id," from ("+@countsql+")temptemptemp "+@countordersql
END
ELSE
BEGIN
set @countsql="insert mytemptable(id1,id2) select 0,id from ("+@countsql+")temptemptemp "+@countordersql
END
execute (@countsql)
select @minid=min(id) from mytemptable
set @beginid=convert(varchar(20),@minid+(@currentpage-1)*@pagesize)
set @endid=convert(varchar(20),@minid+@currentpage*@pagesize-1)
IF (@type=1)
BEGIN
set @sql="select * from ("+@sql+")temptemptemp where id in ( select id1 from mytemptable where id > ="+@beginid+" and id < ="+@endid+")"
END
ELSE
BEGIN
set @sql="select * from ("+@sql+")temptemptemp where id in ( select id2 from mytemptable where id > ="+@beginid+" and id < ="+@endid+")"
END
execute (@sql)
select @total=count(*) from mytemptable
delete from mytemptable
IF (@total>0)
BEGIN
return @total
END
COMMIT TRAN
RETURN 0
go
===========================================================
原理说明:
1. 存储过程pageUtil根据countsql,把对应的id插入到临时表mytemptable(根据type的不同,type=1 Int型 插入到id1字段,type=2 varchar 型 插入到id2字段)
2. 一般的分页数据是有顺序的,这时候的order就可以放到countordersql中,可以按照自定义的方式排序,countsql里的select语句也可以查询多个字段为后面的order做准备,这也是countsql中必须要有 as id的原因。
3.执行countsql将数据插入到mytemptable
4.根据分页参数换算出当前页在mytemptable中的索引 @beginid ,@endid,拼sql串。并执行此sql串。
5. mytemptable的数据数即查询记录总条数,删除mytemptable中的数据,返回总条数。
============================================================
调用例子:
/*******
***分页查询某个用户的所有订单,要求按照时间倒序排序
*****/
public HashMap<Object,Object> getUserConsumeRecord(String username, int pagesize,int currentpage) {
String countsql=" select a.ordernumber as id,a.createdate as createdate from orderform a where a.username='"+username+"' ";
String countordersql=" order by createdate desc ";
String sql="select a.ordernumber as id, a.merchantid,a.orderid,a.chargeamount,a.payamount," +
" from orderform a " +
" where a.username='"+username+"' ";
return this.getPage(2, countsql,countordersql, sql, pagesize, currentpage);
}
/******
**********调用存储过程pageUtil的通用方法***
***********/
public HashMap<Object,Object> getPage(int type,String countsql,String countordersql,String sql,int pagesize,int currentpage)
{
HashMap<Object,Object> result=new HashMap<Object,Object>();
result.put("pagesize", pagesize);
result.put("currentpage", currentpage);
Connection connection=null;
Context context=null;
try
{
connection=getConnection();//获取数据库连接,使用时自行修改
java.sql.CallableStatement cs = connection.prepareCall("{?= call pageUtil(?,?,?,?,?,?)}");
cs.registerOutParameter(1, java.sql.Types.INTEGER);
cs.setInt(2, type);
cs.setString(3, countsql);
cs.setString(4, countordersql);
cs.setString(5, sql);
cs.setInt(6, pagesize);
cs.setInt(7, currentpage);
ResultSet data= cs.executeQuery();
List<HashMap<String,Object>> list=new ArrayList<HashMap<String,Object>>();
while(data.next())
{
int datasize=data.getMetaData().getColumnCount();
HashMap<String,Object> thisdata=new HashMap<String,Object>();
for(int i=1;i<=datasize;i++)
{
thisdata.put(data.getMetaData().getColumnName(i), data.getObject(i));
}
data.getMetaData().getColumnCount();
System.out.println(data.getMetaData().getColumnCount());
System.out.println(data.getString("id"));
list.add(thisdata);
}
int ret=cs.getInt(1);
result.put("totalrecord",ret);
result.put("data", list);
}catch(Exception e)
{
System.out.println(e);
}
finally
{
//关闭数据库连接,使用时自己修改
}
return result;
}
============================================================
注意:mytemptable的锁级别为表锁。
用户需要持有 mytemptable的select insert delete 权限。而这个表数据不重要,分配此权限安全隐患不高。