目錄
1.帶空值的排列
2.Top/Bottom N查詢
3.First/Last排名查詢
4.按層次查詢
一、帶空值的排列
解決排列的數據中含有空值的。NULL爲最大值,這是我們不想見到的!
SQL> select deptno,ename,sum(sal) sal_sum,
sum(sum(sal)) over (partition by deptno ) total,
rank () over (partition by deptno order by sum(sal) desc) rank
from emp group by deptno,ename;
DEPTNO ENAME SAL_SUM TOTAL RANK
------ ---------- ---------- ---------- ----------
10 KING 5000 8564.59 1
10 CLARK 2450 8564.59 2
10 MILLER 1114.59 8564.59 3
20 SCOTT 3000 9953.8 1
20 FORD 3000 9953.8 1
20 JONES 2053.8 9953.8 3
20 ADAMS 1100 9953.8 4
20 SMITH 800 9953.8 5
30 JAMES 8450 1
30 BLAKE 2850 8450 2
30 ALLEN 1600 8450 3
30 TURNER 1500 8450 4
30 WARD 1250 8450 5
30 MARTIN 1250 8450 5
14 rows selected
下面修改後:
SQL> select deptno,ename,sum(sal) sal_sum,
sum(sum(sal)) over (partition by deptno ) total,
rank () over (partition by deptno order by sum(sal) desc
NULLS LAST ) rank
from emp group by deptno,ename;
DEPTNO ENAME SAL_SUM TOTAL RANK
------ ---------- ---------- ---------- ----------
10 KING 5000 8564.59 1
10 CLARK 2450 8564.59 2
10 MILLER 1114.59 8564.59 3
20 SCOTT 3000 9953.8 1
20 FORD 3000 9953.8 1
20 JONES 2053.8 9953.8 3
20 ADAMS 1100 9953.8 4
20 SMITH 800 9953.8 5
30 BLAKE 2850 8450 1
30 ALLEN 1600 8450 2
30 TURNER 1500 8450 3
30 WARD 1250 8450 4
30 MARTIN 1250 8450 4
30 JAMES 8450 6
14 rows selected
NULLS LAST/FIRST告訴Oracle讓空值排名最後後第一。
注意是NULLS,不是NULL。
二、Top/Bottom N查詢:
在日常生活中我們經常會遇到這樣的查詢,找出工資前五名的人員。
SQL> select t.*, rownum from (select * from emp order by sal desc) t where rownum<5;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ROWNUM
----- ---------- --------- ----- ----------- --------- --------- ------ ----------
7900 JAMES CLERK 7698 1981-12-03 30 1
7839 KING PRESIDENT 1981-11-17 5000.00 10 2
7788 SCOTT ANALYST 7566 1987-04-19 3000.00 20 3
7902 FORD ANALYST 7566 1981-12-03 3000.00 20 4
以上爲子查詢對sal進行排序,SAL空值用前面的方法解決
SQL> select t.*, rownum from (select * from emp order by sal desc NULLS LAST) t where rownum<5;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ROWNUM
----- ---------- --------- ----- ----------- --------- --------- ------ ----------
7839 KING PRESIDENT 1981-11-17 5000.00 10 1
7788 SCOTT ANALYST 7566 1987-04-19 3000.00 20 2
7902 FORD ANALYST 7566 1981-12-03 3000.00 20 3
7698 BLAKE MANAGER 7839 1981-05-01 2850.00 30 4
以上爲前4名的排列結果
使用分析函數操作如下:
SQL> select * from (select t.*,rank() over (order by sal desc NULLS LAST) rank from emp t) a where rownum<5 ;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO RANK
----- ---------- --------- ----- ----------- --------- --------- ------ ----------
7839 KING PRESIDENT 1981-11-17 5000.00 10 1
7902 FORD ANALYST 7566 1981-12-03 3000.00 20 2
7788 SCOTT ANALYST 7566 1987-04-19 3000.00 20 2
7698 BLAKE MANAGER 7839 1981-05-01 2850.00 30 4
以上爲爲分析函數操作結果
三、First/Last排名查詢:
找出按部門分組工資總計,最高工資是多少,與最低工資是多少.
SQL> select deptno, sum(sal),
min(sal) keep(dense_rank first order by sal desc nulls last ) first,
min(sal) keep(dense_rank last order by sal desc ) last
from emp group by deptno order by deptno;
DEPTNO SUM(SAL) FIRST LAST
------ ---------- ---------- ----------
10 8564.59 5000 1114.59
20 9953.8 3000 800
30 8450 2850 1250
SQL> select max(sal),min(sal) from emp;
MAX(SAL) MIN(SAL)
---------- ----------
5000 800
這裏有幾個看起來比較疑惑的地方:
①爲什麼這裏要用min函數
②Keep這個東西是幹什麼的
③fist/last是幹什麼的
④dense_rank和dense_rank()有什麼不同,能換成rank嗎?
首先解答一下第一個問題:min函數的作用是用於當存在多個First/Last情況下保證返回唯一的記錄。假如我們去掉會有什麼樣的後果呢?
select deptno, sum(sal),
keep(dense_rank first order by sal desc nulls last ) first,
keep(dense_rank last order by sal desc ) last
from emp group by deptno order by deptno
keep(dense_rank first order by sal desc nulls last ) first,
*
ORA-00907: missing right parenthesis
接下來看看第2個問題:keep是幹什麼用的?從上面的結果我們已經知道Oracle對排名的結果只“保留”2條數據,這就是keep的作用。告訴Oracle只保留符合keep條件的記錄。
那麼什麼纔是符合條件的記錄呢?這就是第3個問題了。dense_rank是告訴Oracle排列的策略,first/last則告訴最終篩選的條件。
第4個問題:如果我們把dense_rank換成rank呢?
select deptno, sum(sal),
max(sal) keep(rank first order by sal desc nulls last ) first,
max(sal) keep(rank last order by sal desc ) last
from emp group by deptno order by deptno
max(sal) keep(rank first order by sal desc nulls last ) first,
*
ORA-02000: missing DENSE_RANK keyword
四、按層次查詢:
統計出工資前1/5之的人員的名單.使用NTILE分析函數,把所有工資分爲5份,爲1的哪一份就是我們想要的結果:
SQL> select empno,ename,sum(sal),
ntile(5) over (order by sum(sal) desc nulls last) til
from emp
group by empno,ename;
EMPNO ENAME SUM(SAL) TIL
----- ---------- ---------- ----------
7839 KING 5000 1
7788 SCOTT 3000 1
7902 FORD 3000 1
7698 BLAKE 2850 2
7782 CLARK 2450 2
7566 JONES 2053.8 2
7499 ALLEN 1600 3
7844 TURNER 1500 3
7521 WARD 1250 3
7654 MARTIN 1250 4
7934 MILLER 1114.59 4
7876 ADAMS 1100 4
7369 SMITH 800 5
7900 JAMES 5
14 rows selected
如果需要找出前25%的用戶資料,哪就只需要NTILE(4)就可以了!