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

how can I fetch even or odd records from a table?

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

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

第一个只显示员工的第一条记录table。而第二个查询完美无缺。拜托,谁能解释一下rownum是如何工作的??。

这是因为 rownum 的一个特点。它是一个 pseudo-column 应用于查询返回的结果集。 (这就是为什么 WHERE ROWNUM > 1 总是错误的。)

在这种情况下,使用 ROWNUM 会导致查询在 WHERE 子句 returns 为假时停止。所以这个 returns 没有行(因为 0 只对偶数行返回):

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

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

任何允许在不计算 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
/

" how bellow query fetches only first two records from table."

通过COUNT STOPKEY操作的奇观。查询知道需要多少行;它 returns 行(并分配 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> 

您的问题是 rownum 的工作原理。

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

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;

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