不同數據庫的分頁查詢語句有着較大區別,其中MySQL數據的limit offset語法最為簡單,而SQL Server數據庫和Oracle數據庫的分頁就比較復雜了。
網上常見的SQL Server和Oracle數據庫的分頁語句都或多或少對表結構有要求,比如必須有遞增的主鍵ID等。
當我們不能確定所連查詢數據表的表結構(比如表是客戶動態提供的)時,如何以一種通用且高效的方式在不同數據庫上實現分頁查詢功能呢?
解決方案1:使用JDBC的通用分頁功能
第一步:利用java.sql.Statement#setMaxRows方法,設置本次查詢的最大記錄數。
第二步:查詢結束后,利用java.sql.ResultSet#absolute方法,跳過前面不屬於查詢頁的記錄。
這種方法的優點是簡單通用。它的缺點也很明顯,就是性能問題,比如查詢最后一頁數據時,JDBC實現原理是先查出所有數據,然后跳過前面頁的數據,性能損傷很大。
如果你確定你所處的業務場景,用戶通常只會觸發前幾頁的查詢(比如搜索場景:如果前幾頁沒有自己想要的東西,通常是縮小查詢范圍重新搜索,而不是逐頁往后去查找),那么這種簡單且通用的方法不失為一種性價比較高的選擇。
解決方案2:使用各類數據庫的通用分頁SQL語句
這是Hibernate的解決思路,由於最終將向數據庫發送的是數據庫相關的特定分頁SQL語句,數據庫有充分的信息進行優化,且最終只返回一頁的記錄。
現在問題的關鍵在於各類數據庫的通用(對表結構沒有限制)分頁查詢語句格式是怎樣的呢?
下面將一一介紹。
注:為了便於舉例,下面的SQL語句均實現的是查詢一張名為test表中的column1、column2、column3字段的值,查詢時設置了基於column1的過濾條件,同時可選是否基於column1排序。column1、column2、colum3沒有任何特殊性,讀者可以將下述SQL格式套用在任何表結構上,同時可以豐富過濾條件。
MySQL/MariaDB數據庫(不排序)
SELECT column1, column2, column3 FROM test WHERE column1 = ? LIMIT 1000 OFFSET 0
MySQL/MariaDB數據庫(排序)
SELECT column1, column2, column3 FROM test WHERE column1 = ? ORDER BY column1 ASC LIMIT 1000 OFFSET 0
SQL Server數據庫(不排序)
SELECT column1, column2, column3 FROM (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS ROWNUM,* FROM test WHERE column1 = ?)t WHERE t.ROWNUM > 0 AND t.ROWNUM <= 1000
SQL Server數據庫(排序)
SELECT column1, column2, column3 FROM (SELECT ROW_NUMBER() OVER ( ORDER BY column1 ASC) AS ROWNUM,* FROM test WHERE column1 = ?)t WHERE t.ROWNUM > 0 AND t.ROWNUM <= 1000
Oracle/達夢數據庫(不排序)
SELECT column1, column2, column3 FROM (SELECT ROWNUM RN,t.* FROM (SELECT * FROM test WHERE column1 = ?)t WHERE ROWNUM <= 1000) WHERE RN > 0
Oracle/達夢數據庫(排序)
SELECT column1, column2, column3 FROM (SELECT ROWNUM RN,t.* FROM (SELECT * FROM test WHERE column1 = ? ORDER BY column1 ASC)t WHERE ROWNUM <= 1000) WHERE RN > 0
這種方法的優點是效率高,缺點是需要學習不同種類的數據庫的通用分頁SQL語句格式。
希望本文總結的這幾種常見數據庫的通用分頁SQL格式能夠覆蓋你的需求,為你帶來幫助。
