如何从表中获取偶数或奇数记录?

时间:2015-04-19 13:36:57

标签: sql oracle rownum

我尝试使用以下两个查询显示奇数或偶数记录。

select * from employee a 
    where 1 = mod(rownum,2);
select * from employee 
   where (rowid,1) in (select rowid, mod(rownum,2) 
                       from employee);

第一个只显示employee表的第一条记录。而第二个查询完美。请问,任何人都可以解释rownum如何运作??。

2 个答案:

答案 0 :(得分:2)

这是因为rownum的特殊性。它是pseudo-column,它应用于查询返回的结果集。 (这就是WHERE ROWNUM > 1始终为假的原因。)

在这种情况下,使用ROWNUM会导致查询在WHERE子句返回false时停止。因此,这不返回任何行(因为0仅针对偶数行返回):

select * from employee a 
    where 0 = mod(rownum,2); 

您的第二种方法有一个子查询,它不在WHERE子句中使用ROWNUM,因此允许返回整个表以便在外部查询中进行评估。

任何允许在不评估ROWNUM的情况下实现整个结果集的方法都可行。这也会产生你想要的结果:

select * from
    (select a.*, rownum as rn from employee a)
where mod(rn,2) = 1
/

正如@DavidAldridge在他的评论中指出的那样,没有ORDER BY子句,结果集基本上是随机的。 ROWNUM与ORDER BY不兼容,所以为了保证订购使用分析函数ROW_NUMBER()。

select * from
    (select a.*
            , row_number() over (order by a.emp_id)  as rn 
     from employee a)
where mod(rn,2) = 0
/

  

“bellow查询如何仅从表中获取前两个记录。”

通过COUNT STOPKEY操作的奇迹。查询知道预期的行数;它返回行(并指定ROWNUM的值),直到达到该限制。

我们可以在EXPLAIN PLAN中看到这一点。没有过滤器:

SQL> explain plan for 
  2      select * from emp;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 3956160932

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     3 |   111 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| EMP  |     3 |   111 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this statement (level=2)

12 rows selected.

SQL> 

以下是where rownum <= 2的计划。请注意所选行的差异:

SQL> explain plan for 
  2      select * from emp
  3      where rownum <= 2;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1973284518

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     2 |    74 |     3   (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY     |      |       |       |            |          |
|   2 |   TABLE ACCESS FULL| EMP  |     3 |   111 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM<=2)

Note
-----
   - dynamic sampling used for this statement (level=2)

18 rows selected.

SQL> 

答案 1 :(得分:1)

您的问题是rownum如何运作。

rownum与表格中的其他列不同;它是一个伪列。它仅对最终结果集中的行增加。因此,获得第二行的着名示例是:

where rownum = 2

永远不会满足此条件,因为第一行输出的rownum设置为1。所以,第一行得到了进程。 rownum为1. where失败。处理第二行,rownum仍为1(因为结果集仍为空),并且where失败。等等。

最安全的解决方案是使用row_number()

select *
from (select a.*, row_number() over (order by rowid) as seqnum
      from employee a 
     ) a
where mod(seqnum, 2) = 1;

这表现得像你期望的那样。

说实话,以下内容也是如此:

select *
from (select a.*, rownum as seqnum
      from employee a 
     ) a
where mod(seqnum, 2) = 1;

子查询中没有过滤,行编号按预期顺序分配。