ROWNUM偽列
ROWNUM
是一個偽列,它是根據每次查詢的結果動態生成的一列遞增編號,表示 Oracle 從表中選擇該行的順序,選擇的第一行ROWNUM
為1,第二行ROWNUM
為2,以此類推。
注意1:
ROWNUM
偽列是在WHERE
子句之前生成的,就是說它并不是在執行了WHERE
子句過濾之后再對數據編號
比如在執行WHERE
子句,結果數據是這樣的:
id | name | age | ROWNUM |
---|---|---|---|
0001 | mary | 18 | 1 |
0002 | mike | 20 | 2 |
0003 | john | 19 | 3 |
0004 | echoo | 16 | 4 |
0005 | susy | 18 | 5 |
0006 | kitty | 21 | 6 |
這時候的ROWNUM
是一列遞增排列的、完整的編號
然后如果執行一個WHERE
子句:WHERE age >18
那數據就變成了:
id | name | age | ROWNUM |
---|---|---|---|
0002 | mike | 20 | 2 |
0003 | john | 19 | 3 |
0006 | kitty | 21 | 6 |
ROWNUM
出現了斷層,不連續了
如果后面再執行一個ORDER BY age DESC
就變成這樣了:
id | name | age | ROWNUM |
---|---|---|---|
0006 | kitty | 21 | 6 |
0002 | mike | 20 | 2 |
0003 | john | 19 | 3 |
ROWNUM
不按順序排了
所以在利用ROWNUM
偽列來對結果集做限制、過濾、排序、分頁等操作的時候一定要注意這個點,不然很容易錯亂;
注意2:
ROWNUM
是一行一行賦值的,只有上一行數據被選擇成功,下一行才會遞增!而且 select 語句也是一行一行選擇的,每 select 一行數據就要進行 where 條件判斷。
比如有這樣一個employees表:
id | name | age |
---|---|---|
0001 | mary | 18 |
0002 | mike | 20 |
0003 | john | 19 |
0004 | kitty | 16 |
0005 | susy | 18 |
0006 | echoo | 21 |
對這個表執行這樣一個SQL:
SELECT * FROM employees WHERE ROWNUM > 1;
這句SQL的預期為取出除第一條數據外的所有數據,但是執行的結果是一條都選不出來,來看執行過程:
① select 出的第一條數據為
id | name | age |
---|---|---|
0001 | mary | 18 |
② ROWNUM
給這條數據賦值,因為是第一條數據,所以從 1 開始,賦值完是這樣的:
id | name | age | ROWNUM |
---|---|---|---|
0001 | mary | 18 | 1 |
③ 進行 WHERE ROWNUM > 1
條件判斷,1>1不滿足條件,所以第一條數據被過濾掉
④ select 第二條數據
id | name | age |
---|---|---|
0002 | mike | 20 |
⑤ ROWNUM
給這條數據賦值,因為上一條數據被過濾掉了,所以還是從 1 開始,賦值完是這樣的:
id | name | age | ROWNUM |
---|---|---|---|
0002 | mike | 20 | 1 |
⑥ 進行 WHERE ROWNUM > 1
條件判斷,1>1不滿足條件,所以這數據也被過濾掉
⑦ ·············
一直如此循環直到結束,都沒有符合條件的數據,所以一條數據都選不出來!
例1:取前10條數據
用ROWNUM
來限制查詢返回的行數,如下例所示:
SELECT * FROM employees WHERE ROWNUM < 11;
WHERE ROWNUM < 11
表示返回查詢數據的前10條;
例2:取排序后的前10條數據
不能夠像下面這樣直接在WHERE
子句后簡單的加上ORDER BY
子句了
SELECT * FROM employees WHERE ROWNUM < 11 ORDER BY age;
因為這里的意思是先執行WHERE
子句選出ROWNUM
1~10的數據,然后再進行排列,和我們預想不符。我們要的是按年齡排序后的前10條數據。
所以應該這樣寫:
SELECT *FROM (SELECT * FROM employees ORDER BY employee_id)WHERE ROWNUM < 11;
這里的意思就是先執行排序,然后對排完序的結果集用ROWNUM
偽列按順序編號,然后取其中ROWNUM
為1~10的那10條數據;
例3:分頁
SELECT *
FROM( SELECT temp_table.*,ROWNUM AS rnFROM (SELECT * FROM employees ORDER BY employee_id) temp_table) result_table
WHERE result_table.rn BETWEEN 起始行數 AND 結尾行數
通過嵌套查詢的方式,把動態的ROWNUM
偽列變成固定的列rn
,然后再用rn
列進行分頁;