• 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

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

  • 相关阅读:
    leetcode231 2的幂 leetcode342 4的幂 leetcode326 3的幂
    leetcode300. Longest Increasing Subsequence 最长递增子序列 、674. Longest Continuous Increasing Subsequence
    leetcode64. Minimum Path Sum
    leetcode 20 括号匹配
    算法题待做
    leetcode 121. Best Time to Buy and Sell Stock 、122.Best Time to Buy and Sell Stock II 、309. Best Time to Buy and Sell Stock with Cooldown 、714. Best Time to Buy and Sell Stock with Transaction Fee
    rand7生成rand10,rand1生成rand6,rand2生成rand5(包含了rand2生成rand3)
    依图
    leetcode 1.Two Sum 、167. Two Sum II
    从分类,排序,top-k多个方面对推荐算法稳定性的评价
  • 原文地址:https://www.cnblogs.com/mm8413/p/1234091.html
Copyright © 2020-2023  润新知