---- 關鍵字: ase 分頁 top identity set rowcount temp table 自增列 偽劣 臨時表
接上篇的關於mysql中的分頁方法,本篇簡單討論在sybase ase中實現資料結果分頁的方式。
本篇介紹三種方法。
第一種:利用游標
程式開發人員比較喜歡使用游標,因為游標的「迴圈」遍歷方式類似程式語言中的for,while,loop語句的實現方法,寫起來比較容易。使用游標一般步驟是:為指定的sql語句定義乙個游標,開啟並移動游標,當移動到指定行號的記錄行之後,再按照需要提取的行數來取資料。從表面上看解決了提取指定範圍資料的問題;但是在實際應用 上,有可能會出現嚴重的效能問題。建立游標需要耗用一定的系統資源之外;當表內的資料量有上千萬甚至到億級別並且需要取大量的資料結果時,用游標每移動一次就取這行資料,然後再移動游標,這個過程將是緩慢的。在使用游標的過程中,系統會給相應的表加上共享鎖,導致鎖競爭而嚴重影響資料庫的效能。
在此不再介紹游標的實現方式,此法比較簡單。
第二種:利用臨時表和標誌列
在sybase ase12.5.3及以後的版本中,我們可以用top關鍵字來限定只返回結果集的前n行資料。在ase12.5.3之前的版本中只能用set rowcount n 的方法來「曲線救國」了。
對於取結果集的第n行至第n+m行資料的要求,我們考慮利用top來實現的話,比較容易想到的是:執行兩次top,再加l兩次倒序排序。
步驟如下:
(1) select top n+m * fromtable_namewhere_clause
order by id 把此結果集派生為表:table_name1
(2) select top m * fromtable_name1order by id desc 把此結果集派生為表:table_name2
(3) select * fromtable_name2order by id desc
上面的3條語句好像能夠實現返回第n行至第n+m行資料的要求。但是,在sybase ase中僅僅利用派生表而不利用臨時表是不能實現這個要求的。
僅僅是ase中的「派生出派生表(derived table)的sql語句中不能含有order by 子句」這個限制就足以使上面的方法行不通。還有乙個限制是,上面的3個步驟中都利用id列進行排序。如果表中沒有可用的排序列時,那麼上述方法也不能用了。不過幸運的是,一般要求對其結果集進行分頁的表都是有可以用作排序的列的(數字型或者日期型)。
繼續尋找乙個能用的方法,下面著重介紹目前通用的ase的分頁思路。此思路的關鍵是產生identity自增列和臨時表。
在ase中大家要是找到了不用臨時表就可以實現分頁的方法請麻煩告訴我一聲。 我嘗試了很多次,都不是很理想。
概括起來主要語句有兩條:
(1) select syb=identity(10),* into #temp_table from table_namewhere_clauseorder_by_clause
(2) select * from #temp_tablewhere_clauseand syb >=nand syb <=n+m
用乙個例子演示一下:
(1) 建立測試表:testa
(2) 插入測試資料
(3) 迴圈插入大量的重複資料,
向表testa迴圈插入已有的資料,15次之後,表testa內的資料達到2^16 = 65536 行。
(4) 利用臨時表 + 自增標誌列來提取第100行至第200行的資料。
語句如下:
select syb=identity(10) ,* into #tempa from testa
select * from #tempa where syb>=100 and syb<=200
drop table #tempa
返回的結果為:
需要將select * from #tempa中的星號*替換為需要返回的列名。
繼續。。。。
當要求返回滿足name='andkylee'的所有行中的第100行至第200行的資料時, 利用
select syb=identity(10),* into #tempa from testa wherename='andkylee'
select * from #tempa where syb>=100 and syb<=200
drop table #tempa
第三種:利用rowcount
此種方法有點不足:必須利用可用作排序的列對結果集進行排序。
還是上面的測試表testa,如果從第9000行開始選擇10行資料,那麼語句如下:
declare @id1 int
set rowcount 9000
select @id1 = id from testa order by id
set rowcount 10
select *from testa where id >= @id1 order by id
set rowcount 0 go
此種方法中核心語句是select @id1=id from testa order by id , 在對錶testa執行查詢的過程中,每讀取一行都會把id列的值賦給@id1這個變數,一直持續到最後一行,@id1這個變數反覆被下一行的id值重新整理,結果只得到最後一樣的id值。如果在此select語句之前加上rowcount的限定,那麼就可用使得@id1這個變數獲得第rowcount行的id值,那麼我們也就獲得了返回範圍結果集的起點了。
後面的 set rowcount 10
select * from testa where id >= @id1 order by id
這兩句實際上可以用一句select top 10 * from testa where id >= @id1 order by id 來替代。
這樣,兩種不同的實現形式為:
declare @id1 int
set rowcount 9000
select @id1 = id from testa order by id
set rowcount 0
select top 10 *from testa where id >= @id1 order by id go
分別看看執行結果吧。
第二種方式的結果:
當然,兩種結果一模一樣。
最後我們測試表testa中的id列順序值打亂, 來看看以上語句的執**況。執行:
id列值打亂之後,前100行的資料為:
我們要求返回滿足name='andkylee'的從第9000行開始的10行資料。
declare @id1 int
set rowcount 9000
select @id1 = id from testa where name='andkylee' order by id
set rowcount 10
select *from testa where name='andkylee' and id >= @id1 order by id
set rowcount 0 go
結果為:
如果不對id列進行排序, 有下面的sql語句:
declare @id1 int
set rowcount 9000
select @id1 = id from testa where name='andkylee'
set rowcount 10
select *from testa where name='andkylee' and id >= @id1
set rowcount 0 go
相應的結果集為:
可以發現這個兩句的結果是不同的。
我想既然都要求返回指定範圍的結果集, 肯定是有排序的依據了, 否則怎麼知道該返回哪個範圍呢?
還有,我給出的第三種方法,在進行表掃瞄的時候,即使不指定排序,也是能夠得到正確結果的。因為表掃瞄時很可能會按照表內資料在物理頁面上的物理位置來返回結果。
就先介紹到這裡吧, 後續可能會根據情況進行補充。
管理結果集的分頁
發布日期 2001年9月24日 問 我怎樣才能使用sql server對結果集的分頁進行管理?答 您經常需要使用一次一頁的形式來顯示乙個結果集,並保證使用者可以輕鬆檢視各個結果集頁面,特別是您在為web站點開發程式的時候。雖然您可以使用ado recordset物件對結果集進行分頁,但是這種解決辦法...
Transact SQL語句遍歷結果集的三種方法
transact sql語句是可以實現遍歷的,有三種方法使用可以通過使用transact sql語句遍歷乙個結果集。下面就為您詳細介紹transact sql語句遍歷結果集的幾種方法,供您參考。第一種方法是使用temp表。使用這種方法您建立的初始的select語句的 快照 並將其用作基礎 指標 例如...
Oracle資料庫大資料集的結果集的型別設定問題
oracle資料庫在大資料集的情況下,其結果集不能設定為 scrollability。否則會產生大量的byte陣列不能夠被gc,導致記憶體溢位。即不能使用 conn.preparestatement sql,resultset.type scroll insensitive,resultset.co...