Oracle查找第n個最大值

在國內外許多Oracle DBA站點上,有很多查找表中第n個最大值的小技巧,這些語句確實相當巧妙,它們都獨闢蹊徑地用到了Oracle表中的一個僞字段“level”。但是在很多情況下,這個語句變成了 美麗的陷阱。如果你想知道爲什麼,並怎樣繞過它,請聽我道來!
研究了幾天,我發現一種衍生算法,即找出第n個和第m個最大值的差(如下):
列表一:
select max(salary) from empdetails
   where level = &n
   connect by prior salary>salary
   start with salary = ( select max(salary) from empdetails);
此後又發現如下算法,利用Oracle的僞字段level,從最大值開始,按值遞減順序,把記錄逐步分層,最後找出第n個最大值和第m個最大值之間的差值。
列表二:
select a.nmax_salary – b.mmax_salary from
  (select max(salary) from empdetails
     where level = &n
     connect by prior salary > salary
     start with salary = (select (max(salary)) from empdetails)
   ) a ,
  (select max(salary) mmax_salary from empdetails
     where level = &m
     connect by prior salary > salary
     start with salary = (select (max(salary)) from empdetails)
   ) b ;
我爲此算法的新奇讚歎了很久,值到一天我想利用這個方法時,才發現這個方法並不如想象中那麼美妙。
我要從60多個不同值中找出第n個最大值時,輸入此語句後,發現如同石沉大海、杳無音訊,屏幕上只有“Statement is running”的提示。爲了瞭解Oracle是怎樣分層的,我輸入如下語句:
列表三:
select lpad(‘ ‘,level)||salary from empdetails
     connect by prior salary > salary
     start with salary = (select (max(salary)) from empdetails) ;
發現屏幕在不斷輸出結果,足足等了十多分鐘,還在不停地滾動,我意識到這算法存在某些問題。
試着分析一下列表三的結果,發現這個語句的回送記錄數與庫中不同數值的個數是指數增長,其公式爲 RecordsRe = 2Rdeferent_value – 1 ,要在60多個不同值中用該算法找出第n個最大值,不知要花多長時間,即使機器不停計算幾百年也不會得到結果。
還有其它方法嗎?當然有,比如定義個遊標,自己作一個計數器,用一段script來完成。假設empdetails表以salary建了一個索引salary_I1,可以用下列語句來完成:
列表四:
select salary from
  (select /* + Index(empdetails,salary_I1) */ Rownum, Row_num, salary
      from empdetails)where Row_num = &1;
在列表四中,用到了Oracle表中的另一個僞字段rownum,還用到了Oracle的優化提示(hint)。要注意Index提示是必須的,如果沒有它,rownum是個僞字段,它不能與整數作相等的運算。Oracle一般按照記錄插入的順序來返回rownum,並不排序,如果用到此hint就可按salary字段排序返回。
列表四找到了按salary字段排序後的第n個記錄的salary值。若表中有多個記錄有相同的salary 值,而我們只要找到第 n 個最大 salary 值,而不是第 n 個記錄,可以用列表5 的語句來實現。
列表五:
select salary from
  (select rownum aa, salary from
     (select distinct salary from empdetails)
   )
   where aa = ( select count (distinct salary ) + 1 - &n from empdetails);
至此,不會再出現列表一和列表二語句運行時的情況了,找第n個最大值的目的終於達到了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章