在Oracle中,用SQL来实现分页有很多种实现方式,但有些语句可能并不是很通用,只能用在一些特殊场景之中;
以下介绍三种比较通用的实现方案;在以下各种实现中,ROWNUM是一个最核心的关键词,在查询时他是一个虚拟的列,取值为1到记录总数的序号;
首先来介绍我们工作中最常使用的一种实现方式:
SELECT * FROM (SELECT ROW_.*, ROWNUM ROWNUM_ FROM (SELECT * FROM TABLE1 WHERE TABLE1_ID = XX ORDER BY GMT_CREATE DESC) ROW_ WHERE ROWNUM <= 20) WHERE ROWNUM_ >= 10;
上面例子中展示的在查询的第二层通过ROWNUM <= 20来控制最大值,在查询的最外层控制最小值。而另一种方式是去掉查询第二层的WHERE ROWNUM <= 20语句,在查询的最外层控制分页的最小值和最大值。此时SQL语句如下,也就是要介绍的第二种实现方式:
SELECT * FROM (SELECT A.*, ROWNUM RN FROM (SELECT * FROM TABLE1 WHERE TABLE1_ID = XX ORDER BY GMT_CREATE DESC) A) WHERE RN BETWEEN 10 AND 20;
以上两种方案完全是通过ROWNUM来完成,下面一种则采用ROWID和ROWNUM相结合的方式,SQL语句如下:
SELECT * FROM (SELECT RID FROM (SELECT R.RID, ROWNUM LINENUM FROM (SELECT ROWID RID FROM TABLE1 WHERE TABLE1_ID = XX ORDER BY GMT_CREATE DESC) R WHERE ROWNUM <= 20) WHERE LINENUM >= 10) T1, TABLE1 T2 WHERE T1.RID = T2.ROWID;
从不断向后翻页这个角度来看,第一种实现方案的成本会越来越高,基本上是线性增长,而第三种方案的成本则不会像前者那样快速,他的增长只体现在通过查询条件读取ROWID的部分;
当然,除了以上提了这些方案,我们还可以用以下的SQL来实现:
SELECT * FROM TABLE1 WHERE TABLE1_ID NOT IN (SELECT TABLE1_ID FROM TABLE1 WHERE ROWNUM <= 10) AND ROWNUM <= 10; SELECT * FROM TABLE1 WHERE ROWNUM <= 20 MINUS SELECT * FROM TABLE1 WHERE ROWNUM <= 10;
………………
注意:当ROWNUM作为查询条件时,他是在order by之前执行,所以要特别小心;
比如我们想查询TABLE1中按TABLE1_ID倒序排列的前10条记录不能用如下的SQL来完成
SELECT * FROM TABLE1 WHERE ROWNUM <= 10 ORDER BY TABLE1_ID DESC;