在實際用途中,常常會要求取最近的幾條紀錄,這就需要先對紀錄進行排序后再取rownum <=
一般常見的
- SELECT *
- FROM (SELECT a.*
- FROM torderdetail a
- ORDER BY order_date DESC)
- WHERE ROWNUM <= 10
而在CSDN曾經發生過討論,關於取近的10條紀錄,有人給出這樣的語句
- SELECT a.*
- FROM torderdetail a
- WHERE ROWNUM <= 10
- ORDER BY order_date DESC
之所以會出現這樣的語句,主要是從效率上的考慮,前面條語句,是要進行全表掃描后再排序,然后再取10條紀錄,后一條語句則不會全表掃描,只會取出10條紀錄,很明顯后條語句的效率會高許多。
那為什么會有爭議呢,那就在於在執行順序上爭議,是先執行排序取10條紀錄,還是取10條紀錄,再排序呢?兩種順序取出來的結果是截然相反 的,Oracle查詢前10條記錄時先排序再取10條,就是取最近的10條,而先取10條,再排序,則取出的最早的10條紀錄。對於此語句,普遍的認為執 行順序是先取10條紀錄再排序的。
所以此語句應該是錯誤。但實際上並非如此,此語句的執行順序和order by的字段有關系,如果你order by 的字段是pk,則是先排序,再取10條(速度比第一種語句快),而排序字段不是PK 時,是先取10條再排序,此時結果就與要求不一樣了,所以第二種寫法一定要在排序字段是主鍵的情況下才能保證結果正確。
Row_number() over()這個分析函數是從9I開始提供的,一般的用途和rownum差不多。
一般寫法row_number() over( order by order_date desc) 生成的順序和rownum的語句一樣,效率也一樣(對於同樣有order by 的rownum語句來說),所以在這種情況下兩種用法是一樣的。
而對於分組后取最近的10條紀錄,則是rownum無法實現的,這時只有row_number可以實現,row_number() over(partition by 分組字段 order by 排序字段)就能實現分組后編號,比如說要取近一個月的每天最后10個訂單紀錄
- SELECT *
- FROM (SELECT a.*,
- ROW_NUMBER () OVER (PARTITION BY TRUNC (order_date) ORDER BY order_date DESC)
- rn
- FROM torderdetail a)
- WHERE rn <= 10
Rownum的另類用法,有時候我們會遇到這種需求,要求輸出當月的所有天數,許多人會煩惱,數據庫里又沒有這樣的表,怎么輸出一個月的所有天數呢?用rownum就能解決:
- SELECT TRUNC (SYSDATE, 'MM') + ROWNUM - 1
- FROM DUAL
- CONNECT BY ROWNUM <= TO_NUMBER
(TO_CHAR (LAST_DAY (SYSDATE), 'dd'))