有關分頁 SQL 的資料很多,有的使用存儲過程,有的使用遊标。本人不喜歡使用遊标,我覺得它耗資、效率低;使用存儲過程是個不錯的選擇,因為存儲過程是經過預編譯的,執行效率高,也更靈活。先看看單條 SQL 語句的分頁 SQL 吧。
方法1:
适用于 SQL Server 2000/2005
SELECTTOP頁大小*FROMtable1WHEREidNOTIN(SELECTTOP頁大小*(頁數-1) idFROMtable1ORDERBYid
)ORDERBYid
方法2:
适用于 SQL Server 2000/2005
SELECTTOP頁大小*FROMtable1WHEREid>(SELECTISNULL(MAX(id),0)FROM(SELECTTOP頁大小*(頁數-1) idFROMtable1ORDERBYid
)A
)ORDERBYid
方法3:
适用于 SQL Server 2005
SELECTTOP頁大小*FROM(SELECTROW_NUMBER()OVER(ORDERBYid)ASRowNumber,*FROMtable1
) AWHERERowNumber>頁大小*(頁數-1)
方法4:
适用于 SQL Server 2005
row_number() 必須制定 order by ,不指定可以如下實作,但不能保證分頁結果正确性,因為排序不一定可靠。可能第一次查詢記錄A在第一頁,第二次查詢又跑到了第二頁。
declare @PageNo int ,@pageSize int;
set @PageNo = 2
set @pageSize=20
select * from (
select row_number() over(order by getdate()) rn,* from sys.objects)
tb where rn >(@PageNo-1)*@pageSize and rn <[email protected]*@pageSize
還有一種方法就是将排序字段作為變量,通過動态SQL 實作,可以改成存儲過程。
declare @PageNo int ,@pageSize int;
declare @TableName varchar(128),@OrderColumns varchar(500), @SQL varchar(max);
set @PageNo = 2
set @pageSize=20
set @TableName = 'sys.objects'
set @OrderColumns = 'name ASC,object_id DESC'
set @SQL = 'select * from (
select row_number() over(order by '[email protected]+' ) rn,* from ' [email protected]+')tb where rn >'+convert(varchar(50),(@PageNo-1)*@pageSize) +' and rn <= '+convert(varchar(50),@PageNo*@pageSize)
print @SQL
exec(@SQL)
方法5:(利用SQL的遊标存儲過程分頁)
适用于 SQL Server 2005
create procedure SqlPager
@sqlstr nvarchar(4000), --查詢字元串
@currentpage int, --第N頁
@pagesize int --每頁行數
as
set nocount on
declare @P1 int, --P1是遊标的id
@rowcount int
exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@[email protected] output
select ceiling(1.0*@rowcount/@pagesize) as 總頁數--,@rowcount as 總行數,@currentpage as 目前頁
set @currentpage=(@currentpage-1)*@pagesize+1
exec sp_cursorfetch @P1,16,@currentpage,@pagesize
exec sp_cursorclose @P1
set nocount off
方法5:(利用MySQL的limit)
适用于 MySQL
mysql中limit的用法詳解[資料分頁常用]
在我們使用查詢語句的時候,經常要傳回前幾條或者中間某幾行資料,這個時候怎麼辦呢?不用擔心,mysql已經為我們提供了這樣一個功能。
select * from table limit [offset,] rows | rows offset offset
limit 子句可以被用于強制 select 語句傳回指定的記錄數。limit 接受一個或兩個數字參數。參數必須是一個整數常量。如果給定兩個參數,第一個參數指定第一個傳回記錄行的偏移量,第二個參數指定傳回記錄行的最大數目。初 始記錄行的偏移量是 0(而不是 1): 為了與 postgresql 相容,mysql 也支援句法: limit # offset #。
mysql> select * from table limit 5,10; // 檢索記錄行 6-15
//為了檢索從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個參數為 -1:
mysql> select * from table limit 95,-1; // 檢索記錄行 96-last.
//如果隻給定一個參數,它表示傳回最大的記錄行數目:
mysql> select * from table limit 5; //檢索前 5 個記錄行
//換句話說,limit n 等價于 limit 0,n。
1. select * from tablename limit 100,15
從100條記錄後開始取15條 (實際取取的是第101-115條資料)
2. select * from tablename limit 100,-1
從第100條後開始-最後一條的記錄
3. select * from tablename limit 15
相當于limit 0,15 .查詢結果取前15條資料
說明,頁大小:每頁的行數;頁數:第幾頁。使用時,請把"頁大小"和"頁大小*(頁數-1)"替換成數字。
其它的方案:如果沒有主鍵,可以用臨時表,也可以用方案三做,但是效率會低。
建議優化的時候,加上主鍵和索引,查詢效率會提高。
通過SQL 查詢分析器,顯示比較:我的結論是:
分頁方案二:(利用ID大于多少和SELECT TOP分頁)效率最高,需要拼接SQL語句
分頁方案一:(利用Not In和SELECT TOP分頁) 效率次之,需要拼接SQL語句
分頁方案三:(利用SQL的遊标存儲過程分頁) 效率最差,但是最為通用