亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > Access > 正文

DataGrid基于Access的快速分頁法

2024-09-07 19:04:57
字體:
來源:轉載
供稿:網友
datagrid是一個功能非常強大的asp.net web服務器端控件,它除了能夠方便地按各種方式格式化顯示表格中的數據,還可以對表格中的數據進行動態的排序、編輯和分頁。使人員從繁瑣的代碼中解放。實現datagrid的分頁功能一直是很多初學asp.net的人感到棘手的問題,特別是自定義分頁功能,實現方法多種多樣,非常靈活。本文將向大家介紹一種datagird控件在access數據庫下的快速分頁法,幫助初學者掌握datagrid的分頁技術。



目前的分頁方法



datagrid內建的分頁方法是使用諸如“select * from <table>”的sql語句從數據庫表中取出所有的記錄到dataset中,datagrid控件綁定到該dataset之后,它的自動分頁功能會幫你從該dataset中篩選出當前分頁的數據并顯示出來,其他沒有用的數據將被丟棄。



還有一種方法是使用自定義分頁功能,先將datagrid的allowcustompaging屬性設置為true,再利用dataadapter的fill方法將數據的篩選工作提前到填充dataset時,而不是讓datagrid幫你篩選:



public int fill (

dataset dataset, //要填充的 dataset。

int startrecord, //從其開始的從零開始的記錄號。

int maxrecords, //要檢索的最大記錄數。

string srctable //用于表映射的源表的名稱。

);




該方法首先將來自查詢處的結果填充到dataset中,再將不需要顯示的數據丟棄。當然,自定義分頁功能需要完成的事情還不止這些,本文將在后面詳細介紹。



以上兩種方法的工作原理都是先從數據庫中取出所有的記錄,然后篩選出有用的數據顯示出來。可見,兩種方法的效率基本上是一致的,因為它們在數據訪問階段并沒有采取有效的措施來減少access對磁盤的訪問次數。對于小數量的記錄,這種開銷可能是比較小的,如果針對大量數據的分頁,開銷將會非常巨大,從而導致分頁的速度非常的慢。換句話說,就算每個datagrid分頁面要顯示的數據只是一個擁有幾萬條記錄的數據庫表的其中10條,每次datagrid進行分頁時還是要從該表中取出所有的記錄。



很多人已經意識到了這個問題,并提出了解決方法:用自定義分頁,每次只從數據庫中取出要顯示的數據。這樣,我們需要在sql語句上下功夫了。由于access不支持真正的存儲過程,在編寫分頁算法上就沒有sql server那么自由了。sql server可以在存儲過程中利用臨時表來實現高效率的分頁算法,受到了廣泛的采用。而對于access,我們必須想辦法在一條sql語句內實現最高效的算法。



用一條sql語句取得某段數據的方法有好幾種。算法不同,效率也就不同。我經過粗略的測試,發現效率最差的sql語句執行時耗費的時間大概是效率最高的sql語句的3倍!而且這個數值會隨著記錄總數的增加而增加。下面將介紹其中兩條常用的sql語句。



為了方便接下來的討論,我們先約定如下:



變量
說明
變量
說明

@pagesize
每頁顯示的記錄總數
@middleindex
中間頁的索引

@pagecount
分頁總數
@lastindex
最后一頁的索引

@recordcount
數據表的記錄總數
@tablename
數據庫表名稱

@pageindex
當前頁的索引
@primarykey
主鍵字段名稱

@firstindex
第一頁的索引
@queryfields
要查詢的字段集




變量
定義

@pagecount
(int)math.ceiling((double)@recordcount / @pagesize)

@firstindex
0

@lastindex
@pagecount – 1

@middleindex
(int)math.ceiling((double)@pagecount / 2) – 1




先讓我們看看效率最差的sql語句:



select top @pagesize * from @tablename

where @primarykey not in (

select top @pagesize*@pageindex @primarykey from @tablename

order by @primarykey asc

) order by @primarykey asc




這條sql語句慢就慢在not in這里,主select語句遍歷的每個@primarykey的值都要跟子select語句的結果集中的每一個@primarykey的值進行比較,這樣時間復雜度非常大。這里不得不提醒一下大家,平時編寫sql語句時應該盡量避免使用not in語句,因為它往往會增加整個sql語句的時間復雜度。



另一種是使用了兩個top和三個order by的sql語句,如下所示:



select * from (

select top @pagesize * from (

select top @pagesize*(@pageindex+1) * from @tablename

order by @primarykey asc

) tablea order by @primarykey desc

) tableb order by @primarykey asc




這條sql語句空間復雜度比較大。如果要顯示的分頁面剛好是最后一頁,那么它的效率比直接select出所有的記錄還要低。因此,對于分頁算法,我們還應該具體情況具體分析,不能一概而論。下面將簡單介紹一下相關概念,如果您對主鍵和索引非常熟悉,可以直接跳過。



有關主鍵和索引的概念



在 access中,一個表的主鍵(primary key,又稱主索引)必然是唯一索引(unique index),它的值是不會重復的。除此之外,索引依據索引列的值進行排序,每個索引記錄包含著一個指向它所引用的數據行的指針,這對order by的執行非常有幫助。我們可以利用主鍵這兩個特點來實現對某條記錄的定位,從而快速地取出某個分頁上要顯示的記錄。



舉個例子,假設主鍵字段為integer型,在數據庫表中,記錄的索引已經按主鍵字段的值升序排好(默認情況下),那么主鍵字段值為“11”的記錄的索引,肯定剛好在值為“12”的記錄的索引前面(假設數據庫表中存在主鍵的值為“12”的記錄)。如果主鍵字段不具備unique約束,數據庫表中將有可能存在兩個或兩個以上主鍵字段的值為“11”的記錄,這樣就無法確定這些記錄之間的前后位置了。



下面就讓我們看看如何利用主鍵來進行數據的分段查詢吧。



快速分頁法的原理



其實該分頁法是從其他方法衍生而來的。本人對原來的方法認真地分析,發現通過優化和改進可以非常有效地提高它的效率。原算法本身效率很高,但缺乏對具體問題的具體分析。同一個分頁算法,可能在取第一頁的數據時效率非常高,但是在取最后一頁的數據時可能反而效率更低。



經過分析,我們可以把分頁算法的效率狀態分為四種情況:

(1)@pageindex <= @firstindex

(2)@firstindex < @pageindex <= @middleindex

(3)@middleindex < @pageindex < @lastindex

(4)@pageindex >= @lastindex



狀態(1)和(4)分別表示第一頁和最后一頁。它們屬于特殊情況,我們不必對其使用特殊算法,直接用top就可以解決了,不然會把問題復雜化,反而降低了效率。對于剩下的兩種狀態,如果分頁總數為偶數,我們可以看作是從數據庫表中刪掉第一頁和最后一頁的記錄,再把剩下的按前后位置平分為兩部分,即前面的一部分,也就是狀態(2),后面的為另一部分,也就是狀態(3);如果分頁總數為奇數,則屬于中間頁面的記錄歸于前面的部分。這四種狀態分別對應著四組sql語句,每組sql語句由升序和降序兩條sql語句組成。



下面是一個數據庫表,左邊第一列是虛擬的,不屬于該數據庫表結構的一部分,它表示相應記錄所在的分頁索引。該表將用于接下來的sql語句的舉例中:



pageindex
itemid
productid
price

0
001
0011
$12

002
0011
$13

1
003
0012
$13

004
0012
$11

2
005
0013
$14

006
0013
$12

3
007
0011
$13

008
0012
$15

4
009
0013
$12

010
0013
$11




由表可得:@pagesize = 2,@recordcount = 10,@pagecount = 5



升序的sql語句



(1)@pageindex <= @firstindex



取第一頁的數據是再簡單不過了,我們只要用top @pagesize就可以取出第一頁要顯示的記錄了。



select top @pagesize @queryfields

from @tablename

where @condition

order by @primarykey asc




(2)@firstindex < @pageindex <= @middleindex



把取數據表前半部分記錄和取后半部分記錄的sql語句分開寫,可以有效地改善性能。后面我再詳細解釋這個原因?,F在看看取前半部分記錄的sql語句。先取出當前頁之前的所有記錄的主鍵值,再從中選出最大值,然后取出主鍵值大于該最大值的前@pagesize條記錄。這里@primarykey的數據類型可以不是integer類型,char、varchar等其他類型照樣可以。



select top @pagesize @queryfields

from @tablename

where @primarykey > (

select max(@primarykey) from (

select top @pagesize*@pageindex @primarykey

from @tablename

where @condition

order by @primarykey asc

) tablea

) where @condition

order by @primarykey asc




例如:@pageindex=1,紅-->黃-->藍







(3)@middleindex < @pageindex < @lastindex



接下來看看取數據庫表中后半部分記錄的sql語句。該語句跟前面的語句算法的原理是一樣的,只是方法稍微不同。先取出當前頁之后的所有記錄的主鍵值,再從中選出最小值,然后取出主鍵值小于該最小值的前@pagesize條記錄。



select * from (

select top @pagesize @queryfields

from @tablename

where @primarykey < (

select min(@primarykey) from (

select top (@[email protected]*(@pageindex+1)) @primarykey

from @tablename

where @condition

order by @primarykey desc

) tablea

) where @condition

order by @primarykey desc

) tableb

order by @primarykey asc




之所以把取數據表前半部分記錄和取后半部分記錄的sql語句分開寫,是因為使用取前半部分記錄的sql語句時,當前頁前面的記錄數目隨頁數遞增,而我們還要從這些記錄中取出它們的主鍵字段的值再從中選出最大值。這樣一來,分頁速度將隨著頁數的增加而減慢。因此我沒有這樣做,而是在當前頁索引大于中間頁索引時(@middleindex < @pageindex)選用了分頁速度隨著頁數的增加而加快的算法。由此可見,假設把所有分頁面劃分為前面、中間和后面三部分,則最前面和最后面的分頁速度最快,最中間的分頁速度最慢。



例如:@pageindex=3,紅 --> 黃 --> 藍







(4)@pageindex >= @lastindex



取最后一頁的記錄可以簡單地使用類似狀態(1)的做法:



select * from (

select top @pagesize @queryfields

from @tablename

where @condition

order by @primarykey desc

) tablea order by @primarykey asc




不過,這樣產生的最后一頁不一定是實際意義上的最后一頁。因為最后一頁的記錄數未必剛好跟@pagesize相等,而上面的sql語句是直接取得倒數的@pagesize條記錄。如果想要精確地取得最后一頁的記錄,應該在先計算出該頁的記錄數,作為top語句的條件:



select * from (

select top (@[email protected]*@lastindex) @queryfields

from @tablename where @condition

order by @primarykey desc

) tablea order by @primarykey asc




降序的sql語句



降序的sql語句跟升序的大同小異,這里就不在羅嗦了j



(1)@pageindex <= @firstindex



select top @pagesize @queryfields

from @tablename

where @condition

order by @primarykey desc




(2)@firstindex < @pageindex <= @middleindex



select top @pagesize @queryfields

from @tablename

where @primarykey < (

select min(@primarykey) from (

select top @pagesize*@pageindex @primarykey

from @tablename

where @condition

order by @primarykey desc

) tablea

) where @condition

order by @primarykey desc




(3)@middleindex < @pageindex < @lastindex



select * from (

select top @pagesize @queryfields

from @tablename

where @primarykey > (

select max(@primarykey) from (

select top (@[email protected]*(@pageindex+1)) @primarykey

from @tablename

where @condition

order by @primarykey asc

) tablea

) where @condition

order by @primarykey asc

) tableb order by @primarykey desc




(4)@pageindex >= @lastindex



select * from (

select top (@[email protected]*@lastindex) @queryfields

from @tablename where @condition order by @primarykey asc

) tablea order by @primarykey desc




如何動態產生上述的sql語句?



看了上面的sql語句之后,相信大家已經基本明白該分頁法的原理了。下面,我們將要設計一個動態生成sql語句的類fastpaging。該類有一個公有靜態方法,它根據您給出的條件動態生成sql語句,作為方法的返回值。



// 產生根據指定字段排序并分頁查詢的 select 語句。

public static string paging(

int pagesize, //每頁要顯示的記錄的數目。

int pageindex, //要顯示的頁的索引。

int recordcount, //數據表中的記錄總數。

string tablename, //要查詢的數據表。

string queryfields, //要查詢的字段。

string primarykey, //主鍵字段。

bool ascending, //是否為升序排列。

string condition //查詢的篩選條件。

) {

stringbuilder sb = new stringbuilder();

int pagecount = getpagecount(recordcount,pagesize); //分頁的總數

int middleindex = getmidpageindex(pagecount); //中間頁的索引

int firstindex = 0; //第一頁的索引

int lastindex = pagecount - 1; //最后一頁的索引



if (pageindex <= firstindex) {

// 代碼略

} else if (pageindex > firstindex && pageindex <= middleindex) {

sb.append("select top ").append(pagesize).append(" ")

.append(queryfields).append(" from ").append(tablename)

.append(" where ").append(primarykey);

if (ascending)

sb.append(" > (").append(" select max(");

else

sb.append(" < (").append(" select min(");

sb.append(primarykey).append(") from ( select top ")

.append(pagesize*pageindex).append(" ").append(primarykey)

.append(" from ").append(tablename);

if (condition != string.empty)

sb.append(" where ").append(condition);

sb.append(" order by ").append(primarykey).append(" ")

.append(getsorttype(ascending)).append(" ) tablea )");

if (condition != string.empty)

sb.append(" and ").append(condition);

sb.append(" order by ").append(primarykey).append(" ")

.append(getsorttype(ascending));

}

else if (pageindex > middleindex && pageindex < lastindex) {

// 代碼略

} else if (pageindex >= lastindex) {

// 代碼略

}

return sb.tostring();

}




除了paging方法還有另外幾個方法:



// 根據記錄總數和分頁大小計算分頁數。

public static int getpagecount(int recordcount, int pagesize) {

return (int)math.ceiling((double)recordcount/pagesize);

}

// 計算中間頁的頁索引。

public static int getmidpageindex(int pagecount) {

return (int)math.ceiling((double)pagecount/2) - 1;

}

// 獲取排序的方式("asc"表示升序,"desc"表示降序)

public static string getsorttype(bool ascending) {

return (ascending ? "asc" : "desc");

}

// 獲取一個布爾值,該值指示排序的方式是否為升序。

public static bool isascending(string ordertype) {

return ((ordertype.toupper() == "desc") ? false : true);

}




讓datagrid工作起來



有了上面的類,實現分頁的工作就簡單多了。首先,我們要將datagrid的allowpaging屬性和allowcustompaging屬性為true,除此之外,為了體現出升序和降序的功能,還需要將allowsorting屬性也設置為true。然后在每次分頁時,我們需要產生一個oledbdatareader對象或dataview對象綁定到datagrid,作為datagrid的數據源。這里需要用fastpaging類的paging方法根據條件產生一個sql語句,并賦給oledbcommand對象的commandtext屬性:



cmd.commandtext = fastpaging.paging(

datagrid1.pagesize,

(int)viewstate["currentpageindex"],

datagrid1.virtualitemcount,

"items",

"itemid, productid, price",

"itemid",

fastpaging.isascending(ordertype),

""

);




在上面的程序段中,viewstate["currentpageindex"]的值在datagrid的page事件處理程序中被更新為e.newpageindex。為了方便處理viewstate的空值,最好把對viewstate["currentpageindex"]的存取操作和空值判斷封裝在一個屬性里。datagrid1. virtualitemcount應該設置為數據庫表中的記錄總數。datagrid通過它和pagesize屬性可以虛擬出datagrid的分頁數。virtualitemcount的值是在page的load事件處理程序中被設置的,而該值的大小需要經過一次數據庫訪問才能得到。為了提高性能,可以只在第一次加載頁面的時候設置該值。



總結



datagrid基于access的快速分頁法到這里就介紹完了。當然,這種方法并不能“包治百病”,可能對于您的要實現的功能,還有其它更好的方法。這就需要大家在平時工作和學習中不斷總結經驗,在解決實際問題時盡可能找到最有效的方法。這也是本文的方法中所貫穿的思想。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产色婷婷国产综合在线理论片a| 久久精品国产亚洲7777| 97香蕉超级碰碰久久免费的优势| 日韩女在线观看| 久久香蕉国产线看观看av| 国产美女久久精品香蕉69| 国产精品久久久久久久美男| 国产精品一香蕉国产线看观看| 国产精品久久久久久久久| 亚洲最大av在线| 国产精品福利久久久| 久久精品亚洲94久久精品| 欧美日韩国产中文精品字幕自在自线| 久久久久这里只有精品| 一区二区三区久久精品| 91地址最新发布| 国内精品久久久久伊人av| 成人在线免费观看视视频| 欧美最猛性xxxx| 一本一道久久a久久精品逆3p| 日韩精品在线免费| 亚洲国产婷婷香蕉久久久久久| 国产999在线观看| 日韩久久免费视频| 欧美性xxxx极品hd欧美风情| 日本久久久久亚洲中字幕| 国内精品久久久久久中文字幕| 日韩精品中文字幕久久臀| 国产成+人+综合+亚洲欧美丁香花| 97香蕉久久夜色精品国产| 久久久久99精品久久久久| 亚洲欧美国产精品久久久久久久| 91成人国产在线观看| 欧美极品少妇xxxxⅹ裸体艺术| 欧美第一页在线| 成年无码av片在线| 中文字幕日韩在线观看| 免费91麻豆精品国产自产在线观看| 久久久久久国产三级电影| 欧美大片欧美激情性色a∨久久| 欧美性xxxx| 中文字幕国产亚洲| 欧美一区二区三区免费观看| 69av视频在线播放| 亚洲男人第一网站| 亚洲永久免费观看| 中文字幕亚洲情99在线| 91在线高清免费观看| 国产精品视频99| 亚洲男人的天堂在线播放| 韩国国内大量揄拍精品视频| 草民午夜欧美限制a级福利片| 91在线免费看网站| 亚洲xxxx妇黄裸体| 97久久超碰福利国产精品…| 91av福利视频| 国产91成人video| 亚洲一区av在线播放| 日韩精品免费一线在线观看| 亚洲一区二区精品| 国产欧美精品日韩| www.日韩系列| 日韩女优人人人人射在线视频| 亚洲国产精品资源| 精品夜色国产国偷在线| 性日韩欧美在线视频| 日韩在线视频一区| 国产精品爽爽爽爽爽爽在线观看| 亚洲www在线观看| 亚洲综合成人婷婷小说| 国产aaa精品| 一区二区欧美激情| 久久久久久久久久久成人| 欧美中文字幕视频| 亚洲精品网址在线观看| 成人在线视频网| 久久久久久久97| 欧美猛少妇色xxxxx| 亚洲欧美在线免费| 伊人久久大香线蕉av一区二区| 国产精品成久久久久三级| 亚洲人午夜精品| 国语自产偷拍精品视频偷| 日韩av一区在线| 久久久久久成人精品| 国产精品日韩欧美| 91经典在线视频| 热久久美女精品天天吊色| 中文字幕精品在线视频| 久久成人人人人精品欧| 久久中国妇女中文字幕| 久久久国产一区| 丝袜美腿精品国产二区| www.亚洲一区| 亚洲免费一级电影| 欧美—级a级欧美特级ar全黄| 91av在线网站| 国产精品ⅴa在线观看h| 亚洲女人被黑人巨大进入| 欧美日韩性生活视频| 国产精品丝袜久久久久久不卡| 亚洲一区二区三区毛片| 九九热r在线视频精品| 亚洲毛片在线观看| 中文字幕在线看视频国产欧美| 欧美性猛交xxxx免费看漫画| 国产欧美在线看| 国产日韩欧美在线视频观看| 成人欧美一区二区三区在线| 96国产粉嫩美女| 欧美日韩国产在线| 久久久国产精彩视频美女艺术照福利| 国产精品电影久久久久电影网| 国产精品日韩欧美综合| 97视频国产在线| 亚洲剧情一区二区| 日韩av电影在线免费播放| 国产成人高潮免费观看精品| 欧美大奶子在线| 欧美激情在线有限公司| 久久99精品视频一区97| 国产成人久久久精品一区| 中文字幕欧美日韩在线| 91理论片午午论夜理片久久| 亚洲色图第三页| 亚洲最大福利视频网站| 久久免费福利视频| 欧美另类高清videos| 成人欧美一区二区三区黑人孕妇| 国产欧美日韩高清| 欧美性猛交xxxx免费看| 一本色道久久综合狠狠躁篇怎么玩| 国产日韩精品综合网站| 欧美国产日本在线| 国产情人节一区| 亚洲男人第一网站| 欧美乱人伦中文字幕在线| 大胆人体色综合| 伊人久久精品视频| 亚洲精品资源美女情侣酒店| 精品国产精品自拍| 高清一区二区三区日本久| 国产成人精品视频| 日韩在线视频中文字幕| 色综合影院在线| 欧美成人免费一级人片100| 欧美国产亚洲精品久久久8v| 欧美一级大胆视频| 成人a视频在线观看| 91在线中文字幕| 成人午夜在线观看| 91日韩在线视频| 91精品久久久久久久久| 国产成人精品一区二区三区| 亚洲影院高清在线| 91美女高潮出水| 精品亚洲一区二区三区| 欧美激情影音先锋| 美女av一区二区| 欧美日韩另类在线| 久久久久久久影视| 欧美一区二区三区免费观看| 久久亚洲精品成人| 亚洲国产天堂久久综合网|