Oracle進階查詢之OVER (PARTITION BY ..)

來源:互聯網
上載者:User

標籤:oracle   where   over(partition by ...order by ...)   分析函數   

為了方便大家學習和測試,所有的例子都是在Oracle內建使用者Scott下建立的。

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

一、rank()/dense_rank() over(partition by ...order by ...)

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

[sql] view plaincopy

  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分別如下:

[sql] view plaincopy

  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 plaincopy

  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)。 

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

小作業:查詢部門最低工資的僱員資訊。

二、min()/max() over(partition by ...)

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

[sql] view plaincopy

  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語句:

[sql] view plaincopy

  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,會得到什麼結果呢?

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

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

[sql] view plaincopy

  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 plaincopy

  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;  


本文出自 “有夢就有希望” 部落格,請務必保留此出處http://mengzhengbin520.blog.51cto.com/7590564/1652890

Oracle進階查詢之OVER (PARTITION BY ..)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.