本文演示asp.net的datagrid和sql server 實現大數據量下的分頁,為了便于實現演示,數據表采用了northwind數據庫的orders表(830條記錄)。
如果數據表中有唯一的自增索引,并且這個字段沒有出現斷號現象。檢索頁面大小的塊區數據就非常簡單了。通過簡單的sql語句就可以實現這個功能: select * from orders where orderid between 10248 and 10253 其中,開始編號為:(currentpageindex - 1) * pagesize 結束編號為:currentpageindex * pagesize
當然,如果這個字段斷號不是很嚴重,而且允許不是很嚴格的按照每頁條數分頁,這樣的方法也是可以用的。
如果這個字段斷號,或者需要按照其他條件排序分頁,就要復雜些了。首先要獲得這個頁面需要顯示的編號,然后再按照這個編號獲得需要的塊區數據。根據編號獲得塊區數據很簡單。不過用下面方式獲得數據排序并不是按照指定的id列表順序,這時候還要附加order by 命令。 select * from orders where orderid in (10248,10249,10250,10251,10252,10253) order by orderid desc 獲得這個頁面需要顯示的編號列表就復雜多了,而且有多種方案:
方案一:維護一個表,這個表記錄需要顯示的這些編號排序順序。(這個表可以是臨時表,也可以是物理表)。下面演示了利用一個全局臨時表。這個全局臨時表記錄需要顯示的編號。注意排序,這里的order by 就是需要顯示的排序順序。 create table ##temptable( iid int identity (1, 1) not null, mainid int not null )
insert ##temptable(mainid) select orderid from orders order by orderid desc
select * from ##temptable
drop table ##temptable -- 實際執行時候,刪除全部臨時表當然不再這里執行。 這個臨時表存在,獲得指定分頁的分塊數據就很簡單了。看下面代碼: create table ##temptable(iid int identity (1, 1) not null,mainid int not null) insert ##temptable(mainid) select orderid from orders order by orderid desc declare @pagesize int,@currpage int,@strsql varchar(2000),@idstr varchar(1000) select @pagesize = 30 select @currpage = 2 select @idstr = '' select @idstr = @idstr + ltrim(rtrim(str(mainid))) + ',' from ##temptable where iid between ((@currpage-1)*@pagesize+1) and @currpage*@pagesize if @idstr <> '' begin select @idstr = left(@idstr,len(@idstr)-1) end select @strsql = 'select * from orders where orderid in ('[email protected]+') order by orderid desc ' exec(@strsql) drop table ##temptable 注意:實際使用這個方案的時候,還要考慮何時更新這個全局臨時表,一般是放到計劃任務中,定時更新這個匯總表。
方案二:每次都去查詢,每次獲得最新的編號順序。由于這時候不存在這個臨時表,書寫獲得需要顯示頁面的編號的字符串就需要點技巧,看下面的代碼: declare @pagesize int,@currpage int, @topnum int,@previous int select @pagesize = 30 select @currpage = 2 select @topnum = @currpage * @pagesize select @previous = (@currpage - 1) * @pagesize declare @i int,@idstr nvarchar(500),@strsql nvarchar(1000) select @i = 0 select @strsql = n'' select @strsql = @strsql + n' select top '+str(@topnum)+ ' @i = @i + 1 ' select @strsql = @strsql + n', @idstr = ' select @strsql = @strsql + n'case when @i > '+str(@previous)+' then @idstr + ltrim(rtrim(str(orderid))) + '','' ' select @strsql = @strsql + n'else n''''end ' select @strsql = @strsql + n'from orders ' select @strsql = ltrim(rtrim(@strsql)) + n' order by orderid desc ' select @idstr = n'' exec sp_executesql @strsql,n'@i int,@idstr varchar(500) output',@i,@idstr output if len(rtrim(ltrim(@idstr))) > 0 begin select @idstr = left(@idstr,len(@idstr)-1) end select @strsql = 'select * from orders where orderid in ('[email protected]+')' exec(@strsql) asp.net 的 datagrid 提供了使用這種分區的數據的方法。 datagrid 通過 allowcustompaging 和 virtualitemcount 屬性支持塊區操作。如果 allowcustompaging 為 true,則 datagrid 不會根據 currentpageindex 計算數據模型中的起始顯示位置。datagrid 將顯示數據模型中的所有數據,而頁導航欄將當前位置報告為 (virtualitemcount+pagesize-1)/pagesize 之 currentpageindex 頁。下面的示例說明此功能。 protected void binddatagrid(int currpage) { string strconn = "data source=(local);integrated security=sspi;database=northwind"; // 請確認 機器名/aspnet 用戶可以訪問northwind數據庫 sqlcommand cmd = new sqlcommand(); sqlconnection conn = new sqlconnection(strconn); sqlparameter[] parms = new sqlparameter[] { new sqlparameter("@pagesize",sqldbtype.int), new sqlparameter("@currpage",sqldbtype.int), new sqlparameter("@searchsql",sqldbtype.nvarchar,128), new sqlparameter("@count",sqldbtype.int), }; parms[0].value = datagrid1.pagesize; parms[1].value = (currpage+1); // 數據庫的分頁算法第一頁是1 datagrid的第一頁是0 parms[2].value = dbnull.value; parms[3].direction = parameterdirection.output; parms[3].value = dbnull.value; dataset ds = new dataset(); try { if (conn.state != connectionstate.open) conn.open(); cmd.connection = conn; cmd.commandtext = "selected_page_list"; cmd.commandtype = commandtype.storedprocedure; if (parms != null) { foreach (sqlparameter parm in parms) cmd.parameters.add(parm); } sqldataadapter da = new sqldataadapter(cmd); da.fill(ds); int aa = convert.toint32(parms[3].value.tostring()); cmd.parameters.clear(); if (currpage == 0) { datagrid1.virtualitemcount = aa; } datagrid1.currentpageindex = currpage; datagrid1.datasource = ds; datagrid1.databind(); } catch(exception ewx) { conn.close(); response.write (ewx.message.tostring()); response.end(); } }
void page_load(object sender, eventargs e ) { if (!ispostback) { binddatagrid(0); // 第一次打開這個頁面,訪問分頁的第一頁 } }