日期:2019/5/22
內容:oracle;數據庫;rownum
數據庫查詢中,常用到"選取前X個"這樣的問題,Oracle沒有TOP關鍵字,這類問題都是通過rownum選取某幾行來完成的。
先說結論
rownum不支持>, >=, =, !=, between...and...這幾個運算符,只能用符號(<、<=)
例子1:選取列表的前三行
例子2:選取列表第10行及以后的記錄
第一次學Oracle,可能都會這么寫:
(錯誤解法warning)
原因:ROWNUM是一個序列,是oracle數據庫從數據文件或緩沖區中讀取數據的順序。它取得第一條記錄則rownum值為1,第二條為2,依次類推。如果你用>,>=,=,between...and這些條件,因為從緩沖區或數據文件中得到的第一條記錄的rownum為1,則被刪除, 接着取下條,可是它的rownum還是1,又被刪除,依次類推,便沒有了數據。
(總的來說,查詢就是逐條篩選,這條不行下一條來上)
(正確解法Tips)
先把rownum的列與table"拼接"作為一個子表來查詢,這樣rownum所在的列就是代表一個屬性(對屬性篩選當然是沒問題的)
注意下圖紅框的部分。
例子3:選取列表中某個值前3的所有記錄
例如:
- 選取薪水SAL前三的人
- 選取成績倒數前三的人
Key Points:
- 前3不代表只是三個,因為有可能存在並列第一/第二
解決思路:先排序(根據實際決定升序還是降序),再選取前3行
例如:選取SAL前3的SNAME
先選出SAL前3的三個數值:
(剛開始學可能會這么寫,錯誤warning:這種寫法是先選列表的1,2,3行再排序)
(你可能會想:嵌套查詢,把排序后的結果作為查詢目標,錯誤warning:最值5000多個並列)
正確解法:
-
先排序去重
select distinct sal from emp order by sal desc;
-
再選出前3的sal
-
再從所有的記錄中篩選sal在上述集合{5000,3000,2975}中的記錄
select [col1, col2] from emp where sal in [set as above]
例子4:選取區間[a,b]的記錄
上述解決了"前n個"即1<=rownum<=n這一類問題,但是並沒有解決a<=rownum<=b這樣更為通用的問題。但其實稍加改變就能夠解決這個問題。
回想一下例子2的操作:把行號rownum"拼接"到一個表,讓rownum變為表的一個屬性。
(截圖不完全)
然后對R屬性篩選
現在來搞點更復雜的:找出薪水排名在2到4的(R, ENAME, SAL),注意考慮排名並列的問題
-
sal排名(2-4:3000,2975,2850)
-
先添加幾個重復排名的(紅框就是我們的篩選目標)
解決步驟:
-
先找出集合{3000,2975,2850}
-
再select [col1,...] from emp where sal in <set as above>
到這一步,篩選區間[a,b]的記錄計算完成了。紅框中即是修改[a,b]的地方。
如果本文有錯誤,歡迎指出。
如果您有更好的解法,歡迎交流。