Oracle高級查詢,over 用法

注:標題中的紅色order by是說明在使用該方法的時候必需要帶上order by。sql

1、rank()/dense_rank() over(partition by ...order by ...)oracle

如今客戶有這樣一個需求,查詢每一個部門工資最高的僱員的信息,相信有必定oracle應用知識的同窗都能寫出下面的SQL語句:spa

[sql]  view plain copy
 
 
 
  1. select e.ename, e.job, e.sal, e.deptno  
  2.   from scott.emp e,  
  3.        (select e.deptno, max(e.sal) sal from scott.emp e group by e.deptno) me  
  4.  where e.deptno = me.deptno  
  5.    and e.sal = me.sal;  

在知足客戶需求的同時,你們應該習慣性的思考一下是否還有別的方法。這個是確定的,就是使用本小節標題中rank() over(partition by...)或dense_rank() over(partition by...)語法,SQL分別以下:.net

[sql]  view plain copy
 
 
 
  1. select e.ename, e.job, e.sal, e.deptno  
  2.   from (select e.ename,  
  3.                e.job,  
  4.                e.sal,  
  5.                e.deptno,  
  6.                rank() over(partition by e.deptno order by e.sal desc) rank  
  7.           from scott.emp e) e  
  8.  where e.rank = 1;  
[sql]  view plain copy
 
 
 
  1. select e.ename, e.job, e.sal, e.deptno  
  2.   from (select e.ename,  
  3.                e.job,  
  4.                e.sal,  
  5.                e.deptno,  
  6.                dense_rank() over(partition by e.deptno order by e.sal desc) rank  
  7.           from scott.emp e) e  
  8.  where e.rank = 1;  

爲何會得出跟上面的語句同樣的結果呢?這裏補充講解一下rank()/dense_rank() over(partition by e.deptno order by e.sal desc)語法。
over:  在什麼條件之上。
partition by e.deptno:  按部門編號劃分(分區)。
order by e.sal desc:  按工資從高到低排序(使用rank()/dense_rank() 時,必需要帶order by不然非法)
rank()/dense_rank():  分級
整個語句的意思就是:在按部門劃分的基礎上,按工資從高到低對僱員進行分級,「級別」由從小到大的數字表示(最小值必定爲1)。 blog

那麼rank()和dense_rank()有什麼區別呢?
rank():  跳躍排序,若是有兩個第一級時,接下來就是第三級。
dense_rank():  連續排序,若是有兩個第一級時,接下來仍然是第二級。排序

小做業:查詢部門最低工資的僱員信息。ip

2、min()/max() over(partition by ...)get

如今咱們已經查詢獲得了部門最高/最低工資,客戶需求又來了,查詢僱員信息的同時算出僱員工資與部門最高/最低工資的差額。這個仍是比較簡單,在第一節的groupby語句的基礎上進行修改以下:it

[sql]  view plain copy
 
 
 
  1. select e.ename,  
  2.          e.job,  
  3.          e.sal,  
  4.          e.deptno,  
  5.          e.sal - me.min_sal diff_min_sal,  
  6.          me.max_sal - e.sal diff_max_sal  
  7.     from scott.emp e,  
  8.          (select e.deptno, min(e.sal) min_sal, max(e.sal) max_sal  
  9.             from scott.emp e  
  10.            group by e.deptno) me  
  11.    where e.deptno = me.deptno  
  12.    order by e.deptno, e.sal;  

上面咱們用到了min()和max(),前者求最小值,後者求最大值。若是這兩個方法配合over(partition by ...)使用會是什麼效果呢?你們看看下面的SQL語句:io

[sql]  view plain copy
 
 
 
  1. select e.ename,  
  2.        e.job,  
  3.        e.sal,  
  4.        e.deptno,  
  5.        nvl(e.sal - min(e.sal) over(partition by e.deptno), 0) diff_min_sal,  
  6.        nvl(max(e.sal) over(partition by e.deptno) - e.sal, 0) diff_max_sal  
  7.   from scott.emp e;  

這兩個語句的查詢結果是同樣的,你們能夠看到min()和max()實際上求的仍是最小值和最大值,只不過是在partition by分區基礎上的。

小做業:若是在本例中加上order by,會獲得什麼結果呢?

3、lead()/lag() over(partition by ... order by ...)

中國人愛攀比,好面子,聞名世界。客戶更是好這一口,在和最高/最低工資比較完以後還以爲不過癮,此次就提出了一個比較變態的需求,計算我的工資與比本身高一位/低一位工資的差額。這個需求確實讓我非常爲難,在groupby語句中不知道應該怎麼去實現。不過。。。。如今咱們有了over(partition by ...),一切看起來是那麼的簡單。以下:

[sql]  view plain copy
 
 
 
  1. select e.ename,  
  2.        e.job,  
  3.        e.sal,  
  4.        e.deptno,  
  5.        lead(e.sal, 1, 0) over(partition by e.deptno order by e.sal) lead_sal,  
  6.        lag(e.sal, 1, 0) over(partition by e.deptno order by e.sal) lag_sal,  
  7.        nvl(lead(e.sal) over(partition by e.deptno order by e.sal) - e.sal,  
  8.            0) diff_lead_sal,  
  9.        nvl(e.sal - lag(e.sal) over(partition by e.deptno order by e.sal), 0) diff_lag_sal  
  10.   from scott.emp e;   

看了上面的語句後,你們是否也會以爲虛驚一場呢(驚出一身冷汗後忽然雞凍起來,這樣容易感冒)?咱們仍是來說解一下上面用到的兩個新方法吧。
lead(列名,n,m):  當前記錄後面第n行記錄的<列名>的值,沒有則默認值爲m;若是不帶參數n,m,則查找當前記錄後面第一行的記錄<列名>的值,沒有則默認值爲null。
lag(列名,n,m):  當前記錄前面第n行記錄的<列名>的值,沒有則默認值爲m;若是不帶參數n,m,則查找當前記錄前面第一行的記錄<列名>的值,沒有則默認值爲null。

下面再列舉一些經常使用的方法在該語法中的應用(注:帶order by子句的方法說明在使用該方法的時候必需要帶order by):

[sql]  view plain copy
 
 
 
  1. select e.ename,  
  2.        e.job,  
  3.        e.sal,  
  4.        e.deptno,  
  5.        first_value(e.sal) over(partition by e.deptno) first_sal,  
  6.        last_value(e.sal) over(partition by e.deptno) last_sal,  
  7.        sum(e.sal) over(partition by e.deptno) sum_sal,  
  8.        avg(e.sal) over(partition by e.deptno) avg_sal,  
  9.        count(e.sal) over(partition by e.deptno) count_num,  
  10.        row_number() over(partition by e.deptno order by e.sal) row_num  
  11.   from scott.emp e;  

重要提示:你們在讀完本片文章以後可能會有點誤解,就是OVER (PARTITION BY ..)比GROUP BY更好,實際並不是如此,前者不可能替代後者,並且在執行效率上前者也沒有後者高,只是前者提供了更多的功能而已,因此但願你們在使用中要根據需求狀況進行選擇。

相關文章
相關標籤/搜索