2015-04-19 71 views
0

我試圖使用下面的兩個查詢顯示奇數或偶數記錄。如何從表格中取出偶數或奇數記錄?

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

第一個只顯示員工表的第一條記錄。而第二個查詢完美地工作。請,任何人都可以解釋rownum是如何工作的?

+1

您應該注意,表中的行必須被視爲沒有順序,除非由數據定義,因此您需要ORDER BY子句才能使其具有意義。 –

回答

2

這是因爲rownum的特殊性。這是一個pseudo-column,它應用於查詢返回的結果集。 (這就是爲什麼WHERE ROWNUM > 1始終爲false)

在這種情況下,使用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 
/

「如何波紋管查詢獲取從表中只有前兩個的記錄。」

通過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> 
+0

謝謝你。對此有一點懷疑。正如你所說,rownum最終被評估。即一旦查詢返回結果集,就會添加rownum。那麼下面的查詢如何從表中只提取前兩條記錄。查詢是來自員工的select *,其中rownum <= 2 – Yugamani

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; 

有子查詢沒有過濾,到了行號按順序分配如你所願。

+1

+1,但您可能會說「對於標識爲所需結果集的一部分的第一行,rownum設置爲1」。 –

+0

@DavidAldridge。 。 。我想你說得很好。 –

+0

謝謝。如果將rownum應用於最終結果集,那麼rownum <= 2如何只返回員工表的前兩條記錄。 – Yugamani