zoukankan      html  css  js  c++  java
  • ASP.NET针对Sybase数据库使用分页技术

     

    ASP.NET针对Sybase数据库使用分页技术

    在编写一个通用数据库操作接口的分页查询时,发现MS SQL ServerOracleMySqlAccess等数据库都有分页查询语句,只有Sybase没有,如果用AseDataAdapter.Fill(dataSet, startRowIndex, maximumRows, "item")方法实现,实际上还是将数据库的所有记录返回的,这样在数据量很大(超过10万条记录)时,速度将无法忍受,经过互联网搜索,发现Sybase 15后加入了Top子句,经测试后发现Top不能使用在子句中,效果与set rowcount一样不能实现分页,如果有哪位大虾知道其语法请予以赐教,搜索中还找到一个分页查询的存储过程,代码如下:

    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<=@maxpages/2 

             begin

                       select @rcount=@ipage*@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=(@maxpages-@ipage+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>=(@maxpages-@ipage)*@num and id<= (@maxpages-@ipage+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<=@maxpages/2

             begin

                       select @rcount=@ipage*@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=(@maxpages-@ipage+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,(@maxpages-@ipage)*@num) || ' and sybid <= ' || convert(varchar,(@maxpages-@ipage+1)*@num)

                       execute (@execsql)

             end

    end

    使用中发现几个问题:

    Ø SQL语句中不能有排序子句;

    Ø 查询表中不能用Identity

    Ø 分页计算存在问题。

    我对该存储过程进行了修改,代码如下:

    /****************************************************************/

    /*   对于大于maxrow条的数据表,排序参数不要为空,               */

    /*   在查询后一半页数时,排序参数使用倒序                       */

    /*   对于有自增量字段的数据表,自增量字段名称参数不能为空,     */

    /*   此时排序参数无效,排序按自增量字段进行排序                 */

    /****************************************************************/

    --drop proc splitpage

    create procedure splitpage

    @fieldclause varchar(8042), --字段

    @tableclause varchar(100),   --表名

    @whereclause varchar(8042), --条件

    @sortclause varchar(180),    --排序

    @identityname varchar(20),   --自增量字段名称

    @ipage int,                  --需要查询页数

    @num int,                    --每页条数

    @totalrow int,               --该查询语句结果的总记录数

    @maxrow int                  --数据表总行数超过此参数后,在查询后一半页数时,排序参数使用倒序

    as   

    begin

             declare @maxpages int   --总页数

             declare @rcount int     --查询的记录数

             declare @bottomstart int    --从后面查询标志,0-从上查询;1-从下查询

             declare @execsql varchar(16384)   --SQL语句

             declare @remainder int --计算数据表总条数的余数变量

            

             select @rcount=@ipage*@num

             select @remainder=@totalrow % @num

             select @maxpages=ceiling(@totalrow/@num)+1

             if @totalrow>@maxrow

             begin

                       if @ipage>@maxpages/2

                       begin

                                select @bottomstart = 1

                       end

                       else

                       begin

                       select @bottomstart = 0

                       end

             end

             else

             begin

                       select @bottomstart = 0

             end

            

             if @identityname=''

             begin

                       select @execsql = 'select sybid=identity(12),' || @fieldclause || ' into #moy_temptable from ' || @tableclause

             end

             else

             begin

                       select @execsql = 'select 100000000000 sybid,' || @fieldclause || ' into #moy_temptable from ' || @tableclause

                       select @bottomstart = 0

             end

            

             if @bottomstart = 0

             begin

                       set rowcount @rcount

             end

             else

             begin

                       select @rcount=(@maxpages-@ipage+1)*@num

                       set rowcount @rcount

             end

            

             if @whereclause<>''

             begin

                       select @execsql = @execsql || ' where ' || @whereclause

             end

             if @sortclause<>''

             begin

                       if @identityname=''

                       begin

                                select @execsql = @execsql || ' order by ' || @sortclause

                       end

                       else

                       begin

                                select @execsql = @execsql || ' order by ' || @identityname

                       end

             end

            

             if @identityname<>''

             begin

                       select @execsql = @execsql || ' update #moy_temptable set sybid=(select count(1) from #moy_temptable b where a.' || @identityname || '>=b.' || @identityname || ') from #moy_temptable a'

             end

            

             if @bottomstart = 0

             begin

                       select @execsql = @execsql || ' select ' || @fieldclause ||' from #moy_temptable where sybid>' || convert(varchar,(@ipage-1)*@num) || ' and sybid <= ' || convert(varchar,@ipage*@num)

             end

             else

             begin

                       select @execsql = @execsql || ' select ' || @fieldclause ||' from #moy_temptable where sybid <= ' || convert(varchar,(@maxpages-@ipage)*@num+@remainder) || ' and sybid > ' || convert(varchar,(@maxpages-(@ipage+1))*@num+@remainder)

             end

             execute (@execsql)

             set rowcount 0

    end

    下面是ASP.NETC#)对该存储过程的调用,代码如下:

            private DataTable GetDataTable(string fieldClause, string tableClause, string whereClause,

                string sortClause, string identityName, int pageIndex, int pageNum, int totalRowCount)

            {

                connection.Open();

                try

                {

                    command.CommandType = CommandType.StoredProcedure;

                    command.CommandText = "splitpage";

                    AseParameterCollection parameters = (AseParameterCollection)command.Parameters;

                    parameters.Add("@fieldclause", AseDbType.VarChar, 8042).Value = fieldClause;

                    parameters.Add("@tableclause", AseDbType.VarChar, 100).Value = tableClause;

                    parameters.Add("@whereclause", AseDbType.VarChar, 8042).Value = whereClause;

                    parameters.Add("@sortclause", AseDbType.VarChar, 180).Value = sortClause;

                    parameters.Add("@identityname", AseDbType.VarChar, 20).Value = identityName;

                    parameters.Add("@ipage", AseDbType.Integer).Value = pageIndex;

                    parameters.Add("@num", AseDbType.Integer).Value = pageNum;

                    parameters.Add("@totalrow", AseDbType.Integer).Value = totalRowCount;

                    parameters.Add("@maxrow", AseDbType.Integer).Value = MaxRowInversionSortNum;

                    AseDataAdapter dataAdapter = new AseDataAdapter((AseCommand)command);

                    DataSet dataSet = new DataSet();

                    dataAdapter.Fill(dataSet, "item");

                    DataTable dataTable = dataSet.Tables["item"];

                    return dataTable;

                }

                finally

                {

                    connection.Close();

                }

            }

            private List<T> GetInfos<T>(DataTable dataTable, bool isPageOverHalf) where T:IBaseClass,new ()

            {

                List<T> result = new List<T>();

                T data=new T();

                if (isPageOverHalf)

                {

                    for (int num = dataTable.Rows.Count - 1; num >= 0; num--)

                   {

                        data = (T)data.GetInfo(dataTable.Rows[num]);

                        result.Add(data);

                    }

                }

                else

                {

                    foreach (DataRow dataRow in dataTable.Rows)

                    {

                        data = (T)data.GetInfo(dataRow);

                        result.Add(data);

                    }

                }

                return result;

            }

    值得注意的是在从下查询时,应该从后向前添加到记录集中,通过下面的函数获取页码及从下查询标志的信息:

            private void GetPageInfo(int totalRowCount, int startRowIndex, int maximumRows, out bool isPageOverHalf, out int pageIndex)

            {

                pageIndex = (startRowIndex + maximumRows) / maximumRows;

                if (totalRowCount <= MaxRowInversionSortNum)

                {

                    isPageOverHalf = false;

                    return;

                }

                decimal dTotalRowCount = (decimal)totalRowCount;

                decimal dPageNum = (decimal)maximumRows;

                decimal pageCount = Math.Ceiling(dTotalRowCount / dPageNum);

                decimal pageHalf = Math.Ceiling(pageCount / (decimal)2);

                if (pageIndex > pageHalf)

                {

                    isPageOverHalf = true;

                }

                else

                {

                    isPageOverHalf = false;

                }

            }

    所需表的建表脚本:

    alter table test_detail

      drop constraint FK_TEST_DET_REFERENCE_TEST_MAI

    go

    if exists (select 1

                from sysobjects

               where id = object_id('test_detail')

                and   type = 'U')

       drop table test_detail

    go

    if exists (select 1

                from sysobjects

               where id = object_id('test_main')

                and   type = 'U')

       drop table test_main

    go

    /*==============================================================*/

    /* Table: test_detail                                           */

    /*==============================================================*/

    create table test_detail (

       detail_id            integer              identity,

       main_id              integer              null,

       detail_name          char(10)             not null,

       constraint PK_TEST_DETAIL primary key (detail_id)

    )

    go

    /*==============================================================*/

    /* Table: test_main                                             */

    /*==============================================================*/

    create table test_main (

       main_id              integer              not null,

       main_name            char(10)             not null,

       constraint PK_TEST_MAIN primary key (main_id)

    )

    go

    alter table test_detail

       add constraint FK_TEST_DET_REFERENCE_TEST_MAI foreign key (main_id)

          references test_main (main_id)

    go

    整个源代码见附件。
    源代码

  • 相关阅读:
    POJ 1082 博弈推规律
    博弈论总结
    POJ 2502 Subway 关键在建图
    【算法设计与数据结构】为何程序员喜欢将INF设置为0x3f3f3f3f?
    一位ACMer过来人的心得
    POJ1724 Dij队列优化邻接表
    Dijkstra队列优化矩阵版
    Uva247 Floyd传递闭包+map处理
    简爬新浪新闻网
    爬href链接
  • 原文地址:https://www.cnblogs.com/mm8413/p/1234091.html
Copyright © 2011-2022 走看看