定位到下一页
当用户定位到下一页时,您要再次使用一般方法执行 cmdNext 命令。这一次,命令的参数是网格中最后一行 ID 列的值。您还需要将页码加 1,以便一般 FillGrid 方法可以使用该数字为该 ID 创建另一个视图状态项。若要将页码加 1,您需要从视图状态中获取旧页码。当进行该操作时,需要将其强制转换为一个整数,因为视图状态中的所有项都存储为对象。“下一页”按钮的代码如下所示:' Visual Basic
Private Sub btnNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNext.Click
   ' Get the page number of the page most recently displayed
   CurrentPage = CType(ViewState("CurrentPage"), Integer)
   CurrentPage += 1
   'Gets the id on current page
   Dim lastid As String = DataGrid1.Items(9).Cells(0).Text
   cmdNext.Parameters("@customerid").Value = lastid
   FillGrid(cmdNext)
End Sub//C#
private void btnNext_Click(object sender, System.EventArgs e)
{
   // Get the page number of the page most recently displayed
   CurrentPage = (int)(ViewState["CurrentPage"]);
   CurrentPage++;
   // Gets the id on current page
   string lastid = DataGrid1.Items[9].Cells[0].Text;
   cmdNext.Parameters["@customerid"].Value = lastid;
   FillGrid(cmdNext);
}
定位到上一页
最后,您需要添加向后移动的代码。这里将使用您存储在视图状态中的信息。首先,获取当前页码然后减 1。然后使用该页码作为名称查找视图状态,获取页上第一行的 ID。使用该 ID 作为 cmdPrevious 命令(将该命令传递给一般 FillGrid 方法)的参数。为了防止离开表的开头,您应该检查页计数不在零以下。另外,您应该启用“下一页”按钮,以防它在上一次定位中被禁用。' Visual Basic
Private Sub btnPrevious_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrevious.Click
   btnNext.Enabled = True
   CurrentPage = CType(ViewState("CurrentPage"), Integer)
   CurrentPage -= 1
   If CurrentPage >= 0 Then
       Dim firstid As String
       firstid = CType(ViewState(CurrentPage.ToString), String)
       cmdPrevious.Parameters("@customerid").Value = firstid
       FillGrid(cmdPrevious)
   End If
End Sub//C#
private void btnPrevious_Click(object sender, System.EventArgs e)
{
   btnNext.Enabled = true;
   CurrentPage = (int)(ViewState["CurrentPage"]);
   CurrentPage--;
   if (CurrentPage >= 0) 
   {
      string firstid;
      firstid = (string)(ViewState[CurrentPage.ToString()]);
      cmdPrevious.Parameters["@customerid"].Value = firstid;
      FillGrid(cmdPrevious);
   }
}

解决方案 »

  1.   

    是在winform中,还是webform?它们的解决方法不一样
      

  2.   

    那么在oracle中的sql呢?oracle 不支持top..
      

  3.   

    是使用WebForm
    To: redcaff_l(热的咖啡)
       没有错呀。我的意思是一次只取10条记录出来,每翻页一次再重新取,
    怎么思路我也知道,但是我就是找不到最后的一页。你说总数可以先将总数得到,然后除与10,整数就是最后一页了,这是没有错。
    但是用SQL语句怎么写法呢想不通!
    To:bluefish922(一天到晚游泳的鱼) 
       我想你应该给我详细一点的答复。如果用其他方法,我也知道,但是我偏偏喜欢用DataGrid来写呀·‘’‘’‘’‘’‘’‘’‘’
      

  4.   

    忘记了很重要的问题。我的SQL是这样写的
    this.cmdNext.CommandText = "SELECT TOP 10 CustomerID, CompanyName, City FROM Customers WHERE (CustomerID > @customerid) ORDER BY CustomerID";
      

  5.   

    其实可以通过创建一个存储过程来实现:-------------------------------------------------------------------------------
    -- upAccountSpecificationGetList_ByPage
    -------------------------------------------------------------------------------
    CREATE PROCEDURE upAccountSpecificationGetList_ByPage
    (
     @nPageSize    int ,
     @nCurrentPage     int,
     @totalNumResults int output
    )
    AS    -- we are creating a temporary table to store the currently
        -- selected page of data. a rowid field has been added to allow
        -- us to track which page we are on (the itemid didn't work
        -- in this case because it is a character data type and it is
        -- much easier to calculate the paging with an int)
        CREATE TABLE #SearchResultsTempTable
        (
    ROWID             int             IDENTITY PRIMARY KEY,
    ROLENAME           varchar(100)   NOT NULL ,
    DESCRIPTION  varchar(255)   NULL,
    STATE varchar(10)
        )
     
        -- copy the search results into the temporary table
        INSERT INTO #SearchResultsTempTable (ROLENAME, DESCRIPTION, STATE)
         SELECT AS_ROLENAME, AS_DESCRIPTION, AS_STATE
         FROM AccountSpecification
     
        -- always return the total number of items found in the search
        SELECT @totalNumResults = @@ROWCOUNT
     
        -- calculate the current page
        DECLARE @nFirstPageRecord  int
        DECLARE @nLastPageRecord  int
        SELECT @nFirstPageRecord = (@nCurrentPage - 1) * @nPageSize
        SELECT @nLastPageRecord = ((@nCurrentPage * @nPageSize) + 1)
     
        -- select the correct page of data with the given page size
        SELECT ROWID, ROLENAME, DESCRIPTION, STATE,
        CASE 
    WHEN ROLENAME IN (select DISTINCT AS_ROLENAME from AccountItem) THEN 'false'
    ELSE 'true'
        END AS CanDelete    FROM #SearchResultsTempTable
        WHERE (ROWID > @nFirstPageRecord) AND (ROWID < @nLastPageRecord)GO
    SET QUOTED_IDENTIFIER OFF 
    GO
    SET ANSI_NULLS ON 
    GO
    在C#程序中,通过:
    pageCount = (int)System.Math.Ceiling((double)totalNumResults / pageSize);
    来计算总页数,想跳到最后一页,则把pageCount的值作为@CurrentPage参数的输入变量即可。
      

  6.   

    呵呵,我们的分页的SQL语句写到组件里去了,是把正常的SQL语句转化过了的具体我不好说,可以说点思路
    select top 10 ...not in (select top 10*(当前页-1)....) group by ...
      

  7.   

    yqlu(不夜天) :可否具体一点点我觉得你的想法有点意思。
    不过能否真的解决我现在的问题。。你是另一种思路来做的。
      

  8.   

    bluefish922(一天到晚游泳的鱼):
      其实我觉的你写跟没有写到组件是一样的。你的意思组件是用其他语言写的吗?还是用dll把它封装,。。
      如果写c#还不是写在cs里。
      做了个function而已  :-)
      

  9.   

    分页的SQL语句写到组件,这能实现吗?谁能提供个例子,感激!!!
      

  10.   

    我们所有的SQL操作都写在组件里的,是这样,在查询页面是一些组合起来的查询的SQL语句,为了所有页面统一操作,就写一个函数来转为分页的语句,我上面说的就是转化后的模式,确实跟组件没关系。
      

  11.   

    如果想要最高效率的话,应该是利用公用的存储过程来实现分页,在存储过程中实现类似bluefish922(一天到晚游泳的鱼)提到的组件的算法。我试验了SqlServer2K上100,000条记录还可以忍受直接到最后一页,但到1000,000条记录就很难忍受直接到最后一页了,可能算法不够好或者应该用Oracel(有自带的分页功能)
      

  12.   

    wenhuayuan(Dobbin Wen) :
      能否给我一个公用的存储过程来实现分页例子
      

  13.   

    http://www.aspxcn.com/dotnetarticle/show.aspx?id=96
      

  14.   

    DataGrid不是有分页的功能吗?
    不好用吗?能不能说说说为什么?
    如果真的不好,我就帮你想象这个问题.
      

  15.   

    DataGrid的分页是采用的一次性读取的装入DataSet,大数据量的时候会占用很大的内存,如果使用自定义的分页就可以使用检索速度最快的DataReader.我现在正在做的一个UserControl就是准备用来作为对DataGrid自定义分页的公用控件,还没做好,但是我比较担心的存储过程中使用到的本地临时表的效率问题
      

  16.   

    想问一个很白痴的问题,存储过程是可以解密的,那是否很不安全?其实我也很想用存储过程,结果经理说存在上述问题不让用。
    MMKK说的是好方法,我们也在考虑作成这样。
      

  17.   

    meetweb(niky):
    我所介绍的这种分页方法还是比较好用的,我在好几个项目的开发中都采用这种技术实现分页。基本思路就是在数据库中创建一个带自增长ID字段的零时表,注意在创建零时表的时候在表名前加“#”,这样SQL Server在实际处理的时候并不会去创建一张真实的表,所以速度很快。应为在该零时表中有一个自增长ID字段,所以很容易就取出从n1~n2的记录,从而实现分页。
      

  18.   

    meetweb(niky) :
    虽然你的表中记录随时有可能增加或着删除,这也没关系。因为在每次取一个分页的数据的时候,在存储过程中必然会执行一下语句:
        CREATE TABLE #SearchResultsTempTable
        (
    ROWID             int             IDENTITY PRIMARY KEY,
    ROLENAME           varchar(100)   NOT NULL ,
    DESCRIPTION  varchar(255)   NULL,
    STATE varchar(10)
        )
    这样就能保证“零时表”中数据和你真是表中数据同步。这种技术我最早是在微软的.net开发经典例子"PetShop"中看到的,刚开始我觉得这样反复创建零时表会影响系统性能,后来发现SQL Server在执行时根本不是真正去创建一个物理的表,因为SQL Server在执行时会进行算法优化。你可以先仿照我贴出来的存储过程实现自己的存储过程,有问题在联系。
      

  19.   

    关键是你的思路自相矛盾。记录随时改变,两个固定的ID之间怎么能保证正好有10条记录(数量是变化的),可见这个算法行不通。你需要实现的功能应该这样描述:1. 从某个主键开始,显示10条记录作为一页。使用SQL:select top 10 * from myTable where {Keys>=Values} order by {Keys},用DataReader读除并绑定DataGrid。2. 用户按键“第一页”,则Select top 1 from myTable order by {Keys},读出记录的主键,执行1.3. 用户按键“下一页”,则从当前显示的页面的最后一条记录的主键,执行1.4. 用户按键“上一页”,则把当前显示的页面的第一条记录的做主键,执行查询Select top 10 * from myTable where {Keys>=Values} order by {Keys} desc。结果中找出最后一条记录做主键,执行1.5. 用户按键“最后一页”,很简单,Select top 10 from myTable order by {Keys} desc,结果中找出最后一条的主键,执行1.
      

  20.   

    推理之,如果你想到第n页,则m=n*10,查找Select top m from myTable order by {Keys},找出最后一个记录作为主键执行1.如果你想知道一共有多少页,则Select count(*) as n from myTable,m=n\10,如果n mod 10=0则一共m页否则m+1页。
      

  21.   

    可见,也能直接可靠地(不丢行显示)实现跳转地n页的功能(包括最后一页),只是页号越大效率低,越接近DataGrid的分页功能。
      

  22.   

    在跳转第n页,如果n>(总页数/2)时,则m=(总页数-n+1)*10,Select top m from myTable order by {Keys} desc,找出最后一个记录作为主键执行1.
      

  23.   

    上面凡是查询中有desc的行的>=都应该是<=呀!  真是衰呀!
      

  24.   

    要是用存储过程,则仿照上述方法就更快了。1.给出主键,查询下面的10条记录。2.给出主键,自动查询前面10条记录的头,然后返回此头开始的10条记录。3.查表的头10条记录。4.(仿照2,从最后一条记录开始)查表的后10条记录。5.返回页数。6.给出页号n,仿照上面算法找出n页开头,返回10条记录。
    这样在Web用户控件中就简单了一点,只需要处理各种按钮的事件,不必考虑数据处理了。而且省下了一半网络通讯时间(但是我觉得这个时间不重要,因为最多10条记录通讯量很小耶)。
      

  25.   

    100万条记录,一个Select top 10定位只需要查找一个磁盘块(在20个顺序查找之内),而upAccountSpecificationGetList_ByPage存储过程却需要扫描一半的磁盘块,因为它是顺序查找。因此,只要你的Select都用到主键,就是连续进行100个查询(不考虑编译时间)都比顺序查找快。这个存储过程不过是在服务器做了DataGrid做的事,省了网络传送时间但是没有提高算法效率。
      

  26.   

    所谓“顺序查找”还是我估计太好了。原来哪个存储过程先经所有记录顺序复制一遍(然后在查找),天呀!比顺序查找(数读过的行数)还慢一被!说“临时表”就是数据库没有实际创建的表可是有点天方夜谭的味道。用户用SQL不能访问并不意味着数据库没有实际创建自己用的表吧?
      

  27.   

    你要是不关心磁盘读写(造成必须首先顺序处理临时表的每一条记录)的效率,可以这么干:把前x个记录找出来形成a,把a的后10条记录找出来就齐了!若有last描述符可以这样写:select last 10 * from (select top n * from myTable),就是页号乘以10,很方便把!何必编那么复杂的存储过程呢?但是,数据库在处理SQL时自动为(select top n * form myTable)建立临时表,这就是问题之所在。
      

  28.   

    不能肯定是本地数据库,又需要简单地使用DataReader,怎么能用游标?使用游标,还不如在存储过程中作,至少不用把每一条记录顺序读到Web程序所在的服务器上。存储过程能做到游标的功能,因此不必考虑将超过50条记录读到Web服务器上的任何方法。关键是如果算法能够避免顺序处理,不产生临时表,或者可以保证产生的临时表不多于50条记录,我觉得就可以接受。我的算法只需要产生最多10条记录的临时表(Select top 10 from myTable order by {Keys} desc,结果中找出最后一条的主键,执行1.),两次查询都利用到主键索引。这必建立不确定的n条记录的临时表和整个复制数据库成为临时表的两类方法好很多。当有1万条记录时,好算法可能用时0.1秒,坏方法用时3秒,考虑Web处理其它功能的时间,用户感觉不出问题;当有50万条记录时,好算法仍然只需要0.3秒(理论上应该是0.1*log2秒,不考虑其它系统原因),但是坏算法可能需要2分半钟才能出来(理论上应该是3*50秒,不考虑其它系统原因)。
      

  29.   

    打错了。好算法仍然只需要0.3秒(理论上应该是0.1*log5/log2秒,不考虑其它系统原因),但是坏算法可能需要1分半钟才能出来(理论上应该是3*50/2秒,不考虑其它系统原因)。
      

  30.   

    To: w_rose(w_rose) 
       感谢你的热情解答,你不能说是思路自相矛盾,这可是microsoft.com提供教程的一个分页的算法。我想把它完善一下。
      

  31.   

    在这里的话。你 要怎么样才能绑定数据呢。假如我在页面上要增加,删除,查询的操作的话。我到要看看你怎么写法。
    一大堆的判断都写不出来。。不过吗最后一页的想法不错
    5. 用户按键“最后一页”,很简单,Select top 10 from myTable order by {Keys} desc,结果中找出最后一条的主键,执行1.