最近學習Oracle,老師講了三個比較典型的問題,做一下總結,也便於以后復習.
下圖顯示的是三個題的題干和要查詢的結果:
===========================================第一題============================
找到員工表中工資最高的前三名:
先說明一個現象:
1 SQL> select rownum,ename from emp; 2 3 ROWNUM ENAME 4 ---------- ---------- 5 1 SMITH 6 2 ALLEN 7 3 WARD 8 4 JONES 9 5 MARTIN 10 6 BLAKE 11 7 CLARK 12 8 SCOTT 13 9 KING 14 10 TURNER 15 11 ADAMS 16 12 JAMES 17 13 FORD 18 14 MILLER
如果在加上order by排序的條件限制:
1 SQL> select rownum ,ename,sal from emp order by sal desc; 2 3 ROWNUM ENAME SAL 4 ---------- ---------- ---------- 5 9 KING 5000 6 13 FORD 3000 7 8 SCOTT 3000 8 4 JONES 2975 9 6 BLAKE 2850 10 7 CLARK 2450 11 2 ALLEN 1600 12 10 TURNER 1500 13 14 MILLER 1300 14 3 WARD 1250 15 5 MARTIN 1250 16 11 ADAMS 1100 17 12 JAMES 950 18 1 SMITH 800
加上order by 之后rownum 依舊沒有變化,說明rownum是基於原始表emp進行排序的 ,固定住了,所以如下使用rownum<=3 來取得Top3是錯誤的:
SQL> select rownum,empno,ename,sal 2 from emp 3 where rownum<=3 4 order by sal desc; ROWNUM EMPNO ENAME SAL ---------- ---------- ---------- ---------- 2 7499 ALLEN 1600 3 7521 WARD 1250 1 7369 SMITH 800
只要是表中的數據內容沒有變,每條記錄對應的行號rownum就不會變....
這個地方可以引出Oracle中的分頁問題:
具體可以看我在博客中的總結:
http://www.cnblogs.com/DreamDrive/p/4025112.html
把這個select ename,sal from emp order by sal desc查詢的結果集再看成一個新表
用rownum就會對這個新表進行排序.排序的rownum按照查詢的順序來展示.
select rownum,ename,sal from (select ename,sal from emp order by sal desc) where rownum < 4 ROWNUM ENAME SAL ---------- ---------- ---------- 1 KING 5000 2 SCOTT 3000 3 FORD 3000
===========================================第二題===================================
找到員工表中薪水大於本部門平均薪水的員工
SQL> select e.empno,e.ename,e.sal,d.avgsal from emp e,(select deptno,avg(sal) avgsal from emp group by deptno) d where e.deptno=d.deptno and e.sal>d.avgsal; EMPNO ENAME SAL AVGSAL ---------- ---------- ---------- ---------- 7499 ALLEN 1600 1566.66667 7566 JONES 2975 2175 7698 BLAKE 2850 1566.66667 7788 SCOTT 3000 2175 7839 KING 5000 2916.66667 7902 FORD 3000 2175
e.deptno = empavg.deptno and e.sal > empavg.salavg
翻譯下來就是:第一個條件是本部門的員工,第二個是薪水大於部門的平均薪水
還有一種不用group by分組函數也能查詢到
叫:相關子查詢
相關子查詢:將主查詢中的某些值作為參數傳遞給子查詢.
相關子查詢對外邊的主表有一個要求,必須有一個別名.
先不看上面結果的第四列(AVGSAL),可以很容易的查詢到
select empno,ename, sal from emp e
然后查詢某個部門的平均工資:
select avg(sal) from emp where deptno = ?
需要確定這個deptno是什么!
結合上面兩個語句
select empno,ename, sal from emp e
where e.sal >( select avg(sal) from emp where deptno = ?)
這個問好?應該代表的是查詢的當前員工所在的部門號傳給這個問號.
變成:
select empno,ename, sal from emp e
where e.sal > (select avg(sal) from emp where deptno = e.deptno);
然后主查詢列上要加上所在部門平均工資
把上面的最后一句查詢部門的平均工資拷貝到主查詢列上.就可以了.
SQL> select empno,ename, sal,(select avg( sal) from emp where deptno = e.deptno) avgsal from emp e where e.sal>(select avg( sal) from emp where deptno = e.deptno); EMPNO ENAME SAL AVGSAL ---------- ---------- ---------- ---------- 7499 ALLEN 1600 1566.66667 7566 JONES 2975 2175 7698 BLAKE 2850 1566.66667 7788 SCOTT 3000 2175 7839 KING 5000 2916.66667 7902 FORD 3000 2175
===============================================第三題=======================
統計每年入職的員工的個數!
select count(*) from emp where decode(substr(to_char(hiredate,'yyyy-mm-dd'),3,2)80 decode(substr(to_char(hiredate,"yyyy-mm-dd"),3,4),'81',count+1) SQL> select count(*) , 2 sum(decode(to_char(hiredate,'RR'),'80',1,0)) "1980", 3 sum(decode(to_char(hiredate,'RR'),'81',1,0)) "1981", 4 sum(decode(to_char(hiredate,'RR'),'87',1,0)) "1987" 5 from emp; COUNT(*) 1980 1981 1987 ---------- ---------- ---------- ---------- 14 1 10 2