`
孙健坤
  • 浏览: 42238 次
  • 性别: Icon_minigender_1
  • 来自: 长春
最近访客 更多访客>>
社区版块
存档分类
最新评论

使用rownum三层循环实现Oracle的分页

阅读更多

 

(一)分页实现及性能

Oracle的分页查询语句基本上可以按照本文给出的格式来进行套用。

 

分页查询格式:

SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21

其中最内层的查询SELECT * FROM TABLE_NAME表示不进行翻页的原始查询语句。ROWNUM <= 40RN >= 21控制分页查询的每页的范围。

上面给出的这个分页查询语句,在大多数情况拥有较高的效率。分页的目的就是控制输出结果集大小,将结果尽快的返回。在上面的分页查询语句中,这种考虑主要体现在WHERE ROWNUM <= 40这句上。

选择第2140条记录存在两种方法,一种是上面例子中展示的在查询的第二层通过ROWNUM <= 40来控制最大值,在查询的最外层控制最小值。而另一种方式是去掉查询第二层的WHERE ROWNUM <= 40语句,在查询的最外层控制分页的最小值和最大值。这是,查询语句如下:

SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
)
WHERE RN BETWEEN 21 AND 40

对比这两种写法,绝大多数的情况下,第一个查询的效率比第二个高得多。

这是由于CBO优化模式下,Oracle可以将外层的查询条件推到内层查询中,以提高内层查询的执行效率。对于第一个查询语句,第二层的查询条件WHERE ROWNUM <= 40就可以被Oracle推入到内层查询中,这样Oracle查询的结果一旦超过了ROWNUM限制条件,就终止查询将结果返回了。

而第二个查询语句,由于查询条件BETWEEN 21 AND 40是存在于查询的第三层,而Oracle无法将第三层的查询条件推到最内层(即使推到最内层也没有意义,因为最内层查询不知道RN代表什么)。因此,对于第二个查询语句,Oracle最内层返回给中间层的是所有满足条件的数据,而中间层返回给最外层的也是所有数据。数据的过滤在最外层完成,显然这个效率要比第一个查询低得多。

上面分析的查询不仅仅是针对单表的简单查询,对于最内层查询是复杂的多表联合查询或最内层查询包含排序的情况一样有效。

这里就不对包含排序的查询进行说明了,下一篇文章会通过例子来详细说明。下面简单讨论一下多表联合的情况。对于最常见的等值表连接查询,CBO一般可能会采用两种连接方式NESTED LOOPHASH JOINMERGE JOIN效率比HASH JOIN效率低,一般CBO不会考虑)。在这里,由于使用了分页,因此指定了一个返回的最大记录数,NESTED LOOP在返回记录数超过最大值时可以马上停止并将结果返回给中间层,而HASH JOIN必须处理完所有结果集(MERGE JOIN也是)。那么在大部分的情况下,对于分页查询选择NESTED LOOP作为查询的连接方法具有较高的效率(分页查询的时候绝大部分的情况是查询前几页的数据,越靠后面的页数访问几率越小)。

因此,如果不介意在系统中使用HINT的话,可以将分页的查询语句改写为:

SELECT /*+ FIRST_ROWS */ * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21

()Oracle Top n

SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40 

以上是oracle 实现top n的功能

SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM between 2 and 100

总是返回空记录 

原因:

对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,而且rownum不能以任何表的名称作为前缀。
 
举例说明:
例如表:student(学生)表,表结构为:
ID
       char(6)      --学号
name
    VARCHAR2(10)   --姓名
create table student (ID char(6), name VARCHAR2(100));
insert into sale values('200001',
‘张一’);
insert into sale values('200002',
‘王二’);
insert into sale values('200003',
‘李三’);
insert into sale values('200004',
‘赵四’);
commit;
(1) rownum
对于等于某值的查询条件
如果希望找到学生表中第一条学生的信息,可以使用rownum=1作为条件。但是想找到学生表中第二条学生的信息,使用rownum=2结果查不到数据。因为rownum都是从1开始,但是1以上的自然数在rownum做等于判断是时认为都是false条件,所以无法查到rownum = nn>1的自然数)。
SQL> select rownum,id,name from student where rownum=1;
(可以用在限制返回记录条数的地方,保证不出错,如:隐式游标)
SQL> select rownum,id,name from student where rownum=1;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         1 200001
张一
SQL> select rownum,id,name from student where rownum =2;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
2rownum对于大于某值的查询条件
  
如果想找到从第二行记录以后的记录,当使用rownum>2是查不出记录的,原因是由于rownum是一个总是从1开始的伪列,Oracle 认为rownum> n(n>1的自然数)这种条件依旧不成立,所以查不到记录
SQL> select rownum,id,name from student where rownum >2;
ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
那如何才能找到第二行以后的记录呀。可以使用以下的子查询方法来解决。注意子查询中的rownum必须要有别名,否则还是不会查出记录来,这是因为rownum不是某个表的列,如果不起别名的话,无法知道rownum是子查询的列还是主查询的列。
SQL>select * from(select rownum no ,id,name from student) where no>2;
        NO ID     NAME
---------- ------ ---------------------------------------------------
         3 200003
李三
         4 200004
赵四
SQL> select * from(select rownum,id,name from student)where rownum>2;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
3rownum对于小于某值的查询条件
如果想找到第三条记录以前的记录,当使用rownum<3是能得到两条记录的。显然rownum对于rownum<n(n>1的自然数)的条件认为是成立的,所以可以找到记录。
SQL> select rownum,id,name from student where rownum <3;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
        1 200001
张一
        2 200002
王二
综上几种情况,可能有时候需要查询rownum在某区间的数据,那怎么办呀从上可以看出rownum对小于某值的查询条件是人为true的,rownum对于大于某值的查询条件直接认为是false的,但是可以间接的让它转为认为是true的。那就必须使用子查询。例如要查询rownum在第二行到第三行之间的数据,包括第二行和第三行数据,那么我们只能写以下语句,先让它返回小于等于三的记录行,然后在主查询中判断新的rownum的别名列大于等于二的记录行。但是这样的操作会在大数据集中影响速度。
SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2;
        NO ID     NAME
---------- ------ ---------------------------------------------------
         2 200002
王二
         3 200003
李三
4rownum和排序
Oracle
中的rownum的是在取数据的时候产生的序号,所以想对指定排序的数据去指定的rowmun行数据就必须注意了。
SQL> select rownum ,id,name from student order by name;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         3 200003
李三
         2 200002
王二
         1 200001
张一
         4 200004
赵四
可以看出,rownum并不是按照name列来生成的序号。系统是按照记录插入时的顺序给记录排的号,rowid也是顺序分配的。为了解决这个问题,必须使用子查询
SQL> select rownum ,id,name from (select * from student order by name);
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         1 200003
李三
         2 200002
王二
         3 200001
张一
         4 200004
赵四
这样就成了按name排序,并且用rownum标出正确序号(有小到大)

---
以上为rownum的必学处,为了更好地使用rownum打下基础。

其实, 理解rownum的关键是Oracle 如何执行查询语句. 如果先执行笛卡尔集运算,再执行where条件限制,那么rownum就可以实现 rownum> n(n>=1)的功能. oralce是边执行笛卡尔集运算,边应用选择条件,所以rownum>n(n>1=)永远不成立 ( 网友评论 )

---
自我练习, 嘿嘿 表: BOOKS

select rownum,isbn,title,price from (select * from BOOKS order by price desc);

select *
  from (select rownum ro,b.* from BOOKS b where rownum < 10)
 where ro > 5;
 
 select * from BOOKS where rownum < 10;
 
 select *
   from (select b.*,
                rownum ro
           from BOOKS b
          where rownum < 20
        )
  where ro > 10;
 
  select *
    from (select *
            from BOOKS
            order by TITLE
         )
  where rownum > 8;
 
  select *
    from (select rownum ro,b.*
            from BOOKS b
            order by b.TITLE
         )
  where ro > 8;
 
  select *
    from (select rownum ro,f.*
            from (select *
                    from BOOKS b
                    order by b.title
                 ) f
         )
  where ro > 8 ; 

 

  此文来源于互联网

 

分享到:
评论

相关推荐

    ROWNUM的使用技巧

    另外一种实现方式是使用 ROWNUM 和 MINUS 操作符结合来实现分页查询。例如: ```sql select * from css_bl_view a where capture_phone_num = '(1) 925-4604800' and rownum minus select * from css_bl_view a...

    oracle分页查询

    Oracle 分页查询详解 ...Oracle 分页查询可以使用 ROWNUM、ROW_NUMBER() 和子查询三种方法来实现,each with its own advantages and disadvantages. 选择哪种方法取决于具体的应用场景和性能要求。

    oracle分页程序的实现

    Oracle数据库在处理大量数据时,为了提高查询效率和用户体验,常常需要使用分页查询。分页不仅能够有效地减少网络传输的数据量,还能让用户逐步浏览数据,提高网页加载速度。以下将详细介绍Oracle数据库中实现分页...

    使用jdbc_oracle实现的分页功能

    例如,我们可以创建一个带有LIMIT和OFFSET子句的SQL(Oracle使用ROWNUM实现类似功能)。 ```java String sql = "SELECT * FROM table_name WHERE ROWNUM &lt;= ? AND ROWNUM &gt; ?"; PreparedStatement pstmt = ...

    java实现oracle分页策略

    本文将深入探讨如何使用Java来实现Oracle的分页策略。 首先,我们需要了解分页的基本概念。分页是将大数据集按指定大小(如每页10条或20条记录)分割成多个部分,用户可以逐页浏览,避免一次性加载所有数据导致页面...

    spring mvc实现Oracle分页

    为了实现分页,我们需要编写SQL语句,包含LIMIT或OFFSET关键字(Oracle中使用ROWNUM和子查询实现类似功能),以限制返回的记录数量。 在Controller层,Spring MVC提供了一个处理HTTP请求并返回响应的机制。在这里,...

    oracle的分页查询

    Oracle 的分页查询 ...Oracle 中的分页查询可以使用 ROWNUM 伪列和 ORDER BY 子句来实现,但是需要注意 ROWNUP 伪列的生成机制和 ORDER BY 子句的影响。同时,我们也可以使用 ROWID 列来实现真正的分页查询。

    oracle-jdbc分页实现(只需传入sql语句即可实现分页)

    Oracle JDBC分页实现是数据库操作中的一个重要环节,尤其是在处理大量数据时,为了提高用户体验和系统性能,分页查询显得尤为重要。Oracle数据库提供了多种方法来实现分页查询,其中包括使用ROWNUM伪列、游标...

    ssh+oracle分页

    在Hibernate中,由于ROWNUM不能与WHERE子句一起使用,我们通常会结合子查询或者使用Oracle的高级分页特性如ROWNUMBER()来实现。例如,通过在子查询中计算行号,然后在外层查询中筛选特定范围的行。 5. **分页组件和...

    如何解决Oracle分页查询中排序与效率问题

    ROWNUM 是 Oracle 专门用于分页查询的伪列,OFFSET Fetch 是 Oracle 12c 及更高版本中引入的分页查询方法。 知识点 2: 分页查询中的排序问题 在分页查询中,如果在 ORDER BY 子句中指定了排序列,会出现排序列不是...

    Oracle&JSP分页和Oracle分页

    不过,ROWNUM有个限制,它不能与WHERE子句一起使用来实现分页,因为Oracle在执行WHERE之前就已经计算了ROWNUM。为了解决这个问题,可以使用子查询或临时表。 另一种更高效的方法是使用Oracle的`ROW_NUMBER()`函数,...

    Oracle的SQL分页实践

    使用JDBC时,可以结合LIMIT和OFFSET子句(Oracle不支持LIMIT,但可以通过ROWNUM模拟)来实现分页,而在Hibernate中,可以使用Criteria API或HQL的`setFirstResult`和`setMaxResults`方法来实现相同的功能。...

    oracle 分页完整代码

    在这个Java和Oracle结合的分页实现中,我们将探讨如何通过Java后端配合Oracle数据库进行有效的分页处理。 首先,Oracle提供了一种名为ROWNUM的伪列,它可以用来对查询结果进行排序和限制。在执行分页查询时,我们...

    mysql、sqlserver、oracle分页,java分页统一接口实现

    Oracle 分页使用 rownum 伪列来实现,rownum 伪列可以指定数据的行号。例如,以下语句将从 mytable 表中获取从第 10 行到第 20 行的数据: ```sql select * from ( select mytable.*, rownum num from ( select *...

    java连接Oracle分页显示

    Oracle数据库支持多种方式进行分页,包括使用ROWNUM、ROWNUM BETWEEN、游标以及通过视图和存储过程。下面我们将详细探讨这些方法,并结合Java如何进行操作。 1. **ROWNUM分页**:Oracle中的ROWNUM伪列可以用来实现...

    oracle 分页类文件

    在Oracle数据库中,由于不支持直接的`LIMIT`子句,通常会通过`ROWNUM`和子查询来实现分页。`ShowSQL.java`可能会包含生成这类复杂SQL的静态方法,接收页码和每页记录数作为输入,返回符合Oracle语法的分页SQL。同时...

    Oracle 分页存储过程 终极版

    在Oracle中,我们通常使用`ROWNUM`伪列实现基本的分页,但这种方式存在效率问题,因为它会先获取所有满足条件的记录,然后再进行限制。对于大数据量,这可能会导致性能下降。 为了解决这个问题,高效的分页存储过程...

    Oracle分页

    本篇将详细介绍如何在Oracle数据库环境中,结合Servlet、AJAX、JSON和jQuery来实现高效、动态的分页功能。 一、Oracle分页原理 Oracle提供了几种不同的分页方式,包括ROWNUM、ROWNUM BETWEEN、ROWNUMBER() OVER()等...

    Oracle All 添加 修改 更新 Oracle分页 emp表 存储过程实现

    在Oracle中,我们可以利用ROWNUM伪列配合子查询来实现分页。 以下是一个简单的分页查询存储过程的实现步骤: 1. **创建存储过程**: 在Oracle中,创建存储过程的语法如下: ```sql CREATE OR REPLACE PROCEDURE...

    Oracle 3种分页SQL方法比较

    本文将详细探讨三种常用的Oracle分页SQL方法:ROWNUM、ROWNUM结合子查询以及新引入的Oracle 12c的FETCH NEXT WITH OFFSET语法。这三种方法各有优缺点,适用于不同的场景。 1. ROWNUM方法: ROWNUM是Oracle中最基础...

Global site tag (gtag.js) - Google Analytics