數據庫查詢返回特定結果即分頁查詢

1 幾種不一樣數據庫的不一樣的分頁寫法:

a mysql php

a) 查詢前n條記錄
select * from table_name limit 0,n
b) 查詢第n條到第m條
select * from table_name limit n,m

b oracle  html

a)查詢前n條記錄
select * from table_name where rownum
b)查詢第m條到第n條記錄:
select * from (select a.*,a.rownum rn from table_name where rownum<n) where rn>m
c sqlserver
a)查詢前n條記錄:
select top n * from table_name;
b)查詢第n條到第m條記錄:
select top n * from (select top m * from table_name order by column_name) a order by column_name desc

2 oracle rownum的用法

對於rownum來講它是oracle系統順序分配爲從查詢返回的行的編號,返回的第一行分配的是1,第二行是2,依此類推,這個僞字段能夠用於限制查詢返回的總行數,並且rownum不能以任何表的名稱做爲前綴。 java

(1) rownum 對於等於某值的查詢條件
若是但願找到學生表中第一條學生的信息,可使用rownum=1做爲條件。可是想找到學生表中第二條學生的信息,使用rownum=2結果查不到數據。由於rownum都是從1開始,可是1以上的天然數在rownum作等於判斷是時認爲都是false條件,因此沒法查到rownum = n(n>1的天然數)。
SQL> select rownum,id,name from student where rownum=1;(能夠用在限制返回記錄條數的地方,保證不出錯,如:隱式遊標) mysql

(2)rownum對於大於某值的查詢條件
   若是想找到從第二行記錄之後的記錄,當使用rownum>2是查不出記錄的,緣由是因爲rownum是一個老是從1開始的僞列,Oracle 認爲rownum> n(n>1的天然數)這種條件依舊不成立,因此查不到記錄。 web

    那如何才能找到第二行之後的記錄呀。可使用如下的子查詢方法來解決。注意子查詢中的rownum必需要有別名,不然仍是不會查出記錄來,這是由於rownum不是某個表的列,若是不起別名的話,沒法知道rownum是子查詢的列仍是主查詢的列。
SQL>select * from(select rownum no ,id,name from student) where no>2; sql

(3)rownum對於小於某值的查詢條件
    若是想找到第三條記錄之前的記錄,當使用rownum<3是能獲得兩條記錄的。顯然rownum對於rownum<n((n>1的天然數)的條件認爲是成立的,因此能夠找到記錄。
SQL> select rownum,id,name from student where rownum <3; 數據庫

    綜上幾種狀況,可能有時候須要查詢rownum在某區間的數據,那怎麼辦呀從上能夠看出rownum對小於某值的查詢條件是人爲true的,rownum對於大於某值的查詢條件直接認爲是false的,可是能夠間接的讓它轉爲認爲是true的。那就必須使用子查詢。例如要查詢rownum在第二行到第三行之間的數據,包括第二行和第三行數據,那麼咱們只能寫如下語句,先讓它返回小於等於三的記錄行,而後在主查詢中判斷新的rownum的別名列大於等於二的記錄行。可是這樣的操做會在大數據集中影響速度。
SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2; 性能優化

(4)rownum和排序
    Oracle中的rownum的是在取數據的時候產生的序號,因此想對指定排序的數據去指定的rowmun行數據就必須注意了。
SQL> select rownum ,id,name from student order by name; session

能夠看出,rownum並非按照name列來生成的序號。系統是按照記錄插入時的順序給記錄排的號,rowid也是順序分配的。爲了解決這個問題,必須使用子查詢
SQL> select rownum ,id,name from (select * from student order by name); oracle

參考文檔:http://blog.csdn.net/mantisxf/article/details/1684805

3 mysql中的limit用法

具體的語法爲:

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。
參考文檔: http://www.phpweblog.net/peiyinjin/archive/2008/04/15/3199.html


4 mysql的高效分頁寫法

Select a.* from ( 
  select id from table b force index(ind_group_type_time) 
  where b.id=1111 order by b.update_time desc limit  xx, xx
) b, table a where a.id=b.id;

MySQL的limit工做原理就是先讀取n條記錄,而後拋棄前n條,讀m條想要的,因此n越大,性能會越差。 

優化前SQL: SELECT * FROM member ORDER BY last_active LIMIT 50,5 

優化後SQL: SELECT * FROM member INNER JOIN (SELECT member_id FROM member ORDER BY last_active LIMIT 50, 5) USING (member_id) 

分別在於,優化前的SQL須要更多I/O浪費,由於先讀索引,再讀數據,而後拋棄無需的行。而優化後的SQL(子查詢那條)只讀索引(Cover index)就能夠了,而後經過member_id讀取須要的列。

參考文檔:http://willko.iteye.com/blog/670120

5 分頁寫法的頁數計算

總頁數=(總記錄數-1)/每頁顯示的記錄數 +1

關於SQL Server SQL語句查詢分頁數據

好比:要求選取 tbllendlist 中 第3000頁的記錄,每一頁100條記錄。


select top 100 * from tbllendlist

where fldserialNo not in

(

select top 300100 fldserialNo from tbllendlist

order by fldserialNo

)

order by fldserialNo


或者:

SELECT TOP 100 *

FROM tbllendlist

WHERE (fldserialNo >

(SELECT MAX(fldserialNo)

FROM (SELECT TOP 300100 fldserialNo

FROM tbllendlist

ORDER BY fldserialNo) AS T))

ORDER BY fldserialNo


方法1執行速度比較快!

7 sqlserver2005的分頁寫法

SELECT ... 
    FROM 
        (
            SELECT ROW_NUMBER() OVER (ORDER BY ID asc) AS RowNum, ......
            FROM TABLE_NAME 
        ) AS T
    WHERE T.RowNum> 10  and T.RowNum<= 20
或者
WITH DataList AS 
    ( 
        SELECT ROW_NUMBER() OVER (ORDER BY O.ID DESC)AS RowNum, ......
        FROM .....
        WHERE ......
    )
    SELECT ......
    FROM DataList
    WHERE RowNum BETWEEN 10 AND 20

參考文檔:http://callan.iteye.com/blog/422822

strut標籤實現分頁

<form name="form" method="post" action="peopleAction.do">
<table width="400" height="20" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td width="400" valign="middle" bgcolor="#CCCCCC">&nbsp;&nbsp;
        共爲<bean:write name="maxPage"/>  <!-- 輸出總記錄數 -->
        頁&nbsp;
        共有<bean:write name="pageNumber"/>     <!-- 輸出總分頁 -->       
        條&nbsp;
        當前爲第<bean:write name="nonce"/>頁 &nbsp;    <!-- 輸出當前頁數 -->
        <logic:equal name="nonce" value="1">
          首頁
        </logic:equal>             
        <logic:notEqual name="nonce" value="1"> <!-- 若是當前頁碼不等於1 -->
           <a href="people.do?i=0">首頁</a> <!-- 提供首頁超連接 -->
        </logic:notEqual>
            &nbsp;
        <logic:lessEqual name="maxPage" value="${nonce}">   <!-- 若是當前頁碼不小於總頁數 -->
            尾頁                              <!-- 不提供尾頁超連接 -->
        </logic:lessEqual>
        <logic:greaterThan name="maxPage"  value="${nonce}"> <!-- 若是當前頁碼小於總頁數 -->
        <a href="people.do?i=<%=maxPage-1%>">尾頁</a>&nbsp;   <!-- 提供尾頁超連接 -->
        </logic:greaterThan> 
        <logic:equal name="nonce"  value="1">   <!-- 若是當前頁碼等於1 -->
            上一頁                             <!-- 不提供上一頁超連接 -->
        </logic:equal>
        <logic:notEqual name="nonce"  value="1">    <!-- 若是當前頁碼不等於1 -->
            <a href="people.do?i=<%=number-1%>">上一頁</a>   <!-- 提供上一頁超連接 -->
        </logic:notEqual>
        <logic:lessEqual name="maxPage" value="${nonce}">
            下一頁
        </logic:lessEqual>
            <logic:greaterThan name="maxPage" value="${nonce}"> <!-- 若是當前頁面小於總頁數 -->
                <a href="people.do?i=<%=number+1%>">下一頁</a>   <!-- 提供下一頁超連接 -->
        </logic:greaterThan>           
    </td>
</tr>
</table>
</form>

9 Hibernate實現分頁查詢的原理分析

Hibernate 能夠實現分頁查詢,例如: 

從第2萬條開始取出100條記錄 

Query q = session.createQuery("from Cat as c");;  
q.setFirstResult(20000);;  
q.setMaxResults(100);;  
List l = q.list();;

那麼Hibernate底層如何實現分頁的呢?實際上Hibernate的查詢定義在net.sf.hibernate.loader.Loader這個類裏面,仔細閱讀該類代碼,就能夠把問題完全搞清楚。 

Hibernate2.0.3的Loader源代碼第480行如下: 

if (useLimit); sql = dialect.getLimitString(sql);;        
PreparedStatement st = session.getBatcher();.prepareQueryStatement(sql, scrollable);;
public boolean supportsLimit(); {  
  return true;  
}  
public String getLimitString(String sql); {  
  StringBuffer pagingSelect = new StringBuffer(100);;  
  pagingSelect.append(sql);;  
  pagingSelect.append(" limit ?, ?");;  
  return pagingSelect.toString();;  
}

這是net.sf.hibernate.dialect.MySQLDialect,MySQL的專用分頁語句,再來看net.sf.hibernate.dialect.Oracle9Dialect: 


public boolean supportsLimit(); {  
  return true;  
}  
  
public String getLimitString(String sql); {  
  StringBuffer pagingSelect = new StringBuffer(100);;  
  pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");;  
  pagingSelect.append(sql);;  
  pagingSelect.append(" ); row_ where rownum <= ?); where rownum_ > ?");;  
  return pagingSelect.toString();;  
}



Oracle採用嵌套3層的查詢語句結合rownum來實現分頁,這在Oracle上是最快的方式,若是隻是一層或者兩層的查詢語句的rownum不能支持order by 

除此以外,InterbasePostgreSQLHSQL也支持分頁的sql語句,在相應的Dialect裏面,你們自行參考。 

若是數據庫不支持分頁的SQL語句,那麼根據在配置文件裏面 

#hibernate.jdbc.use_scrollable_resultset true 

默認是true,若是你不指定爲false,那麼Hibernate會使用JDBC2.0scrollable result來實現分頁,看Loader430行如下: 

if ( session.getFactory();.useScrollableResultSets(); ); {  
  // we can go straight to the first required row  
  rs.absolute(firstRow);;  
}  
else {  
  // we need to step through the rows one row at a time (slow);  
  for ( int m=0; m<firstRow; m++ ); rs.next();;  
}

若是支持scrollable result,使用ResultSetabsolute方法直接移到查詢起點,若是不支持的話,使用循環語句,rs.next一點點的移過去。 

可見使用Hibernate,在進行查詢分頁的操做上,是具備很是大的靈活性,Hibernate會首先嚐試用特定數據庫的分頁sql,若是沒用,再嘗試Scrollable,若是不行,最後採用rset.next()移動的辦法。 

在查詢分頁代碼中使用Hibernate的一大好處是,既兼顧了查詢分頁的性能,同時又保證了代碼在不一樣的數據庫之間的可移植性。

參考文檔: http://www.iteye.com/topic/261


總結一下:數據庫中mysql和oracle的分頁寫法都不一致,各個數據庫有各自的特色。另外要注意下相關sql的性能優化,特別是針對大數據的翻頁查詢。

相關文章
相關標籤/搜索