我尝试使用以下两个查询显示奇数或偶数记录。
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如何运作??。
答案 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;
子查询中没有过滤,行编号按预期顺序分配。