Oracle復雜查詢及總結
一、復雜查詢
1、 列出至少有一個員工的所有部門編號、名稱,並統計出這些部門的平均工資、最低工資、最高工資。
1、確定所需要的數據表:
- emp表:可以查詢出員工的數量;
- dept表:部門名稱;
- emp表:統計信息;
2、確定已知的關聯字段:
- emp.deptno=dept.deptno;
第一步:找出至少有一個員工的部門編號
SELECT deptno,COUNT(empno) FROM emp GROUP BY deptno HAVING COUNT(empno)>1;
第二步:找到部門名稱,肯定使用部門表,因為現在的數據量較小,所以可以將之前的emp表和dept表兩個進行連接,統一采用多字段分組的方式查詢;
SELECT d.deptno,d.dname,COUNT(e.empno) FROM emp e,dept d WHERE e.deptno=d.deptno(+) GROUP BY d.deptno,d.dname HAVING COUNT(e.empno)>1;
第三步:依然需要繼續統計
SELECT d.deptno,d.dname,COUNT(e.empno),AVG(sal),MIN(sal),MAX(sal) FROM emp e,dept d WHERE e.deptno=d.deptno(+) GROUP BY d.deptno,d.dname HAVING COUNT(e.empno)>1;
2、 列出薪金比“SMITH”或“ALLEN”多的所有員工的編號、姓名、部門名稱、其領導姓名。
1、確定所需要的數據表:
- emp表:查詢出“SMITH”或“ALLEN”工資;
- emp表:最終的顯示需要編號、姓名;
- emp表:領導的姓名,自身關聯;
- dept表:部門名稱;
2、確定已知的關聯字段:
- 雇員和領導:emp.mgr=memp.empno;
- 雇員和部門:emp.deptno=dept.deptno;
第一步:找出“SMITH”或“ALLEN”的工資
SELECT sal FROM emp WHERE ename IN(‘SMITH‘,‘ALLEN‘);
第二步:以上的查詢返回的多行單列的記錄,按照子查詢的要求在WHERE子句中寫合適,所以這個時候將上面的查詢作為一個子查詢出現,繼續查詢符合此要求的員工的編號、姓名。
SELECT e.empno,e.ename FROM emp e WHERE e.sal>ALL( SELECT sal FROM emp WHERE ename IN(‘SMITH‘,‘ALLEN‘));
第三步:查詢出部門的名稱,引入部門表,同時增加消除笛卡爾積的條件
SELECT e.empno,e.ename,d.dname FROM emp e,dept d WHERE e.sal>ALL( SELECT sal FROM emp WHERE ename IN(‘SMITH‘,‘ALLEN‘)) AND e.deptno=d.deptno;
第四步:領導的信息需要emp表自身關聯
SELECT e.empno,e.ename,d.dname,m.ename FROM emp e,dept d,emp m WHERE e.sal>ALL( SELECT sal FROM emp WHERE ename IN(‘SMITH‘,‘ALLEN‘)) AND e.deptno=d.deptno AND e.mgr=m.empno(+);
3、 列出所有員工的編號、姓名及其直接上級的編號、姓名,顯示的結果按領導年工資的降序排列。
1、確定所需要的數據表:
- emp表:員工的編號、姓名;
- emp表:領導的編號、姓名、計算年薪;
2、確定已知的關聯字段:emp.mgr=memp.empno;
SELECT e.empno,e.ename,m.empno,m.ename,(m.sal+NVL(m.comm,0))*12 income FROM emp e,emp m WHERE e.mgr=m.empno(+) ORDER BY income DESC;
4、列出受雇日期早於其直接上級的所有員工的編號、姓名、部門名稱、部門位置、部門人數。
1、確定所需要的數據表:
- emp表:雇員的編號、姓名;
- emp表:求出領導的工作日期;
- dept表:部門名稱、位置;
- emp表:統計部門人數;
2、確定已知的關聯字段:
- 雇員和部門:emp.deptno=dept.deptno;
- 雇員和領導:emp.mgr=memp.empno;
第一步:列出受雇日期早於其直接上級的所有員工的編號、姓名 —— 自身關聯emp表。
SELECT e.empno,e.ename FROM emp e,emp m WHERE e.mgr=m.empno(+) AND e.hiredate<m.hiredate;
第二步:加入部門信息,繼續引入部門表
SELECT e.empno,e.ename,d.dname,d.loc FROM emp e,emp m,dept d WHERE e.mgr=m.empno(+) AND e.hiredate<m.hiredate AND e.deptno=d.deptno;
額外提問,此時的笛卡爾積:emp表的14條 * emp表的14條 * dept表的4條;
第三步:統計部門人數,此時由於要使用統計函數,而且以上的查詢也無法再直接出現統計函數,所以使用子查詢完成
SELECT e.empno,e.ename,d.dname,d.loc,temp.count FROM emp e,emp m,dept d,( SELECT deptno dno,COUNT(empno) count FROM emp GROUP BY deptno) temp WHERE e.mgr=m.empno(+) AND e.hiredate<m.hiredate AND e.deptno=d.deptno AND e.deptno=temp.dno;
當查詢顯示的時候需要統計信息,但是又不能直接使用統計函數查詢的話,通過子查詢在FROM子句之後進行統計。
5、列出部門名稱和這些部門的員工信息(數量、平均工資),同時列出那些沒有員工的部門。
1、確定所需要的數據表:
- dept表:部門的信息;
- emp表:求出所有的統計信息;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal) FROM emp e,dept d WHERE e.deptno(+)=d.deptno GROUP BY d.deptno,d.dname,d.loc;
6、列出所有“CLERK”(辦事員)的姓名及其部門名稱,部門的人數,工資等級。
1、確定所需要的數據表:
- emp表:找到辦事員的姓名;
- dept表:部門名稱;
- emp表:統計求出部門的人數;
- salgrade表:查詢工資等級;
2、確定已知的關聯字段:
- emp表和dept表:emp.deptno=dept.deptno;
- emp表和salgrade表:emp.sal BETWEEN salgrade.losal AND salgrade.hisal;
第一步:找到所有辦事員的姓名
SELECT e.ename FROM emp e WHERE job=‘CLERK‘;
第二步:找到部門信息,引入dept表,同時增加消除笛卡爾積的條件
SELECT e.ename,d.dname FROM emp e,dept d WHERE job=‘CLERK‘ AND e.deptno=d.deptno;
第三步:部門人數需要額外的統計,但是本程序的查詢裏面已經不可能繼續使用COUNT()函數,所以寫子查詢統計
SELECT e.ename,d.dname,temp.count FROM emp e,dept d,( SELECT deptno dno,COUNT(empno) count FROM emp GROUP BY deptno) temp WHERE e.job=‘CLERK‘ AND e.deptno=d.deptno AND d.deptno=temp.dno;
第四步:雇員的工資等級,繼續引入salgrade表
SELECT e.ename,d.dname,temp.count,s.grade FROM emp e,dept d,( SELECT deptno dno,COUNT(empno) count FROM emp GROUP BY deptno) temp,salgrade s WHERE e.job=‘CLERK‘ AND e.deptno=d.deptno AND d.deptno=temp.dno AND e.sal BETWEEN s.losal AND s.hisal;
7、列出最低薪金大於1500的各種工作及從事此工作的全部雇員人數及所在部門名稱、位置、平均工資。
1、確定所需要的數據表:
- emp表:最低薪金大於1500的工作肯定需要使用emp表統計求出,以及可以求出雇員人數;
- dept表:求出些雇員所在的部門信息;
- emp表:統計求出部門的平均工資;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
第一步:使用emp表按照job分組,統計最低工資(HAVING)和人數
SELECT e.job,COUNT(e.empno) FROM emp e GROUP BY e.job HAVING MIN(e.sal)>1500;
第二步:要查詢出雇員所在的部門信息,但是以上的查詢能跟dept表有關聯嗎?
以上的查詢和dept表之間並沒有關聯字段,那麽如果沒有關聯字段,一定會有笛卡爾積產生,但是多表查詢必須要消除笛卡爾積,所以必須聯系;
- 以上的查詢可以和emp表的job字段關聯;
- 要引入的dept表也可以和emp表的deptno字段關聯;
SELECT temp.job,temp.count,d.dname,e.ename FROM dept d,( SELECT e.job job,COUNT(e.empno) count FROM emp e GROUP BY e.job HAVING MIN(e.sal)>1500) temp, emp e WHERE e.deptno=d.deptno AND e.job=temp.job;
第三步:求出一個部門的平均工資,使用emp表在子查詢中統計
SELECT temp.job,temp.count,d.dname,e.ename,res.avg FROM dept d,( SELECT e.job job,COUNT(e.empno) count FROM emp e GROUP BY e.job HAVING MIN(e.sal)>1500) temp, emp e,( SELECT deptno dno,AVG(sal) avg FROM emp GROUP BY deptno) res WHERE e.deptno=d.deptno AND e.job=temp.job AND e.deptno=res.dno;
本題目之所以出的如此之復雜,目的是訓練大家尋找關聯字段的能力,但是本題目沒有任何的意義,知道就行了。
8、列出在部門“SALES”(銷售部)工作的員工姓名、基本工資、雇傭日期、部門名稱、假定不知道銷售部的部門編號。
1、確定所需要的數據表:
- emp表:員工姓名、基本工資、雇傭日期;
- dept表:找到銷售部的部門編號、部門名稱;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
SELECT e.ename,e.sal,e.hiredate,d.dname FROM emp e,dept d WHERE e.deptno=d.deptno AND d.dname=‘SALES‘;
9、列出薪金高於公司平均薪金的所有員工,所在部門,上級領導,公司的工資等級。
1、確定所需要的數據表:
- emp表:可以求出公司的平均薪金;
- emp表:員工的信息;
- dept表:部門的信息;
- emp表:領導的信息;
- salgrade表:工資等級;
2、確定已知的關聯字段:
- 雇員和部門:emp.deptno=dept.deptno;
- 雇員和領導:emp.mgr=memp.empno;
- 雇員和工資等級:emp.sal BETWEEN salgrade.losal AND salgrade.hisal;
第一步:求出公司的平均薪金
SELECT AVG(sal) FROM emp;
第二步:將以上的子查詢放在WHERE子句之中,作為一個查詢條件,求出滿足此條件的雇員信息。
SELECT e.empno,e.ename,e.job,e.sal FROM emp e WHERE e.sal>( SELECT AVG(sal) FROM emp);
第三步:找到部門的名稱
SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc FROM emp e,dept d WHERE e.sal>( SELECT AVG(sal) FROM emp) AND e.deptno=d.deptno;
第四步:找到領導的信息
SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc,m.ename FROM emp e,dept d,emp m WHERE e.sal>( SELECT AVG(sal) FROM emp) AND e.deptno=d.deptno AND e.mgr=m.empno(+);
第五步:找到工資等級
SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc,m.ename,s.grade FROM emp e,dept d,emp m,salgrade s WHERE e.sal>( SELECT AVG(sal) FROM emp) AND e.deptno=d.deptno AND e.mgr=m.empno(+) AND e.sal BETWEEN s.losal AND s.hisal;
10、列出與“SCOTT”從事相同工作的所有員工及部門名稱,部門人數。
1、確定所需要的數據表:
- emp表:找到SCOTT的工作;
- emp表:員工的信息;
- dept表:部門名稱;
- emp表:部門人數;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
第一步:找到SCOTT的工作
SELECT job FROM emp WHERE ename=‘SCOTT‘;
第二步:以上的子查詢返回單行單列的數據,所以可以在WHERE子句中出現,以這個條件查找滿足要求的雇員信息
SELECT e.empno,e.ename,e.job FROM emp e WHERE e.job=( SELECT job FROM emp WHERE ename=‘SCOTT‘) AND e.ename<>‘SCOTT‘;
第三步:找到部門名稱
SELECT e.empno,e.ename,e.job,d.dname FROM emp e,dept d WHERE e.job=( SELECT job FROM emp WHERE ename=‘SCOTT‘) AND e.ename<>‘SCOTT‘ AND e.deptno=d.deptno;
第四步:找到部門人數,需要統計,所以在FROM子句之中編寫
SELECT e.empno,e.ename,e.job,d.dname,temp.count FROM emp e,dept d,( SELECT deptno dno,COUNT(empno) count FROM emp GROUP BY deptno) temp WHERE e.job=( SELECT job FROM emp WHERE ename=‘SCOTT‘) AND e.ename<>‘SCOTT‘ AND e.deptno=d.deptno AND temp.dno=e.deptno;
11、列出公司各個工資等級雇員的數量、平均工資。
1、確定所需要的數據表:
- emp表:統計出數據;
- salgrade表:得出工資等級;
2、確定已知的關聯字段:emp.sal BETWEEN salgrade.losal AND s.hisal;
本程序實際上就是一個多字段分組而已,唯一不同的是,將分組條件設置為salgrade表中的字段;
SELECT s.grade,s.losal,s.hisal,COUNT(e.empno),AVG(e.sal) FROM emp e,salgrade s WHERE e.sal BETWEEN s.losal AND s.hisal GROUP BY s.grade,s.losal,s.hisal;
12、列出薪金高於在部門30工作的所有員工的薪金的員工姓名和薪金、部門名稱。
1、確定所需要的數據表:
- emp表:找出所有在30部門工作的雇員的工資;
- emp表:最終顯示的雇員姓名;
- dept表:找到部門名稱;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
第一步:找到30部門工作的雇員的工資
SELECT sal FROM emp WHERE deptno=30;
第二步:高於30部門,使用ALL操作符,引入emp表,查詢姓名和薪金
SELECT e.empno,e.ename FROM emp e WHERE sal>ALL( SELECT sal FROM emp WHERE deptno=30) AND e.deptno=d.deptno;
13、列出在每個部門工作的員工數量、平均工資和平均服務期限。
1、確定所需要的數據表:
- dept表:找到部門信息;
- emp表:統計出數量、平均工資、平均服務年限;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
直接將dept和emp表關聯,使用多字段分組即可,但是對於服務年限需要一個計算過程。
SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal),AVG(MONTHS_BWTWEEN(SYSDATE,e.hiredate)/12) year FROM emp e,dept d WHERE e.deptno(+)=d.deptno GROUP BY d.deptno,d.dname,d.loc;
14、列出所有員工的姓名、部門名稱和工資。
1、確定所需要的數據表:
- emp表:找到員工姓名;
- dept表:部門名稱;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
SELECT e.ename,d.dname,e.sal FROM emp e,dept d WHERE e.deptno=d.deptno;
15、列出所有部門的詳細信息和部門人數。
1、確定所需要的數據表:
- emp表:統計信息;
- dept表:查詢部門信息;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
SELECT d.deptno,d.dname,d.loc,COUNT(e.empno) FROM emp e,dept d WHERE e.deptno(+)=d.deptno GROUP BY d.deptno,d.dname,d.loc;
16、列出各種工作的最低工資及從事此工作的雇員姓名。
1、確定所需要的數據表:
- emp表:統計出各個工作的最低工資;
- emp表:查找出雇員姓名;
第一步:按照職位統計各個職位的最低工資
SELECT job,MIN(sal) FROM emp GROUP BY job;
第二步:將以上的查詢和emp表關聯
SELECT e.ename,e.job,e.sal FROM emp e,( SELECT job,MIN(sal) FROM emp GROUP BY job) temp WHERE e.job=temp.job AND e.sal=temp.min;
17、列出各個部門的MANAGER(經理)的最低薪金、姓名、部門名稱、部門人數。
1、確定所需要的數據表:
- emp表:找到經理的薪金、姓名;
- dept表:部門名稱;
- emp表:統計部門人數;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
第一步:找到所有部門的經理
SELECT deptno,MIN(sal) FROM emp WHERE job=‘MANAGER‘ GROUP BY deptno;
第二步:找到姓名,但是以上的子查詢,不能再出現其他的字段
SELECT e.ename,e.sal FROM emp e,( SELECT deptno dno,MIN(sal) sal FROM emp WHERE job=’MANAGER’ GROUP BY deptno) temp WHERE e.deptno=temp.dno AND e.sal=temp.sal AND e.job=‘MANAGER‘;
第三步:加入部門的名稱信息
SELECT e.ename,e.sal,d.dname FROM emp e,( SELECT deptno dno,MIN(sal) sal FROM emp WHERE job=‘MANAGER‘ GROUP BY deptno) temp,dept d WHERE e.deptno=temp.dno AND e.sal=temp.sal AND e.job=‘MANAGER‘ AND e.deptno=d.deptno;
第四步:統計部門人數
SELECT e.ename,e.sal,d.dname,res.count FROM emp e,( SELECT deptno dno,MIN(sal) sal FROM emp WHERE job=’MANAGER’ GROUP BY deptno) temp,dept d,( SELECT deptno dno,COUNT(empno) count FROM emp GROUP BY deptno) res WHERE e.deptno=temp.dno AND e.sal=temp.sal AND e.job=‘MANAGER‘ AND e.deptno=d.deptno AND res.dno=d.deptno;
18、列出所有員工的年工資,所在部門名稱,按年薪從低到高排序。
1、確定所需要的數據表:
- emp表:統計年工資;
- dept表:部門名稱;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
SELECT e.ename,e.sal*12 income,d.dname FROM emp e,dept d WHERE e.deptno=d.deptno ORDER BY income;
19、查出某個員工的上級主管及所在部門名稱,並要求出這些主管中的薪水超過3000。
1、確定所需要的數據表:
- emp表:員工的信息;
- emp表:領導的信息;
- dept表:部門名稱;
2、確定已知的關聯字段:
- 雇員和部門:emp.deptno=dept.deptno;
- 雇員和領導:emp.mgr=memp.empno;
SELECT DISTINCT m.ename,d.dname,m.sal FROM emp e,emp m,dept d WHERE e.mgr=m.empno AND m.deptno=d.deptno AND m.sal>3000;
20、求出部門名稱中,帶‘S’字符的部門員工的工資合計、部門人數。
1、確定所需要的數據表:
- emp表:進行統計信息;
- dept表:部門名稱;
2、確定已知的關聯字段:emp.deptno=dept.deptno;
SELECT d.dname,SUM(e.sal),COUNT(e.empno) FROM emp e,dept d WHERE e.deptno(+)=d.deptno AND d.dname LIKE ‘%S%’ GROUP BY d.dname;
21、給任職日期超過30年或者在87年雇傭的雇員加薪,加薪原則:10部門增長10%,20部門增長20%,30部門增長30%,依次類推。
UPDATE emp SET sal=(1 + deptno/100)*sal WHERE MONTHS_BETWEEN(SYSDATE,hiredate)/12>30 OR TO_CHAR(hiredate,’yyyy’)=1987;
以上的所有題目作為DML操作的總結,這些題目結果都不重要,關鍵是解決問題的思路,這些只能通過代碼的不斷練習。
二、總結
1、 多表查詢:在進行查詢語句編寫的時候,一定要確定所需要關聯的數據表,而且只要是表的關聯查詢,就一定會存在笛卡爾積的問題,使用關聯字段消除此問題。
在使用多表查詢的時候要考慮到左右連接的問題,Oracle之外的數據庫可以使用SQL:1999語法控制左右連接;
2、 所有的統計函數是用於進行數據統計操作的,而統計要在分組中進行(或者是單獨使用),分組使用GROUP BY子句,是在某一列上存在重復數據的時候才會使用分組操作,而分組後的過濾使用HAVING子句完成,所有的分組函數可以嵌套,但是嵌套之後的分組函數之中不能再有其他的查詢字段,包括分組字段;
3、 子查詢:結合限定查詢、多表查詢、分組統計查詢完成各個復雜查詢的操作,子查詢一般在WHERE和FROM之後出現較多;
4、 數據庫的更新操作一定要受到事務的控制,事務的兩個命令:COMMIT、ROLLBACK,每一個連接到數據庫上的用戶都使用一個SESSION表示;
5、 數據表的分頁查詢顯示依靠ROWNUM偽列,以後在開發之中必定100%要使用。
Oracle復雜查詢及總結