第九章高階子查詢
第九章
巢狀子查詢:可以理解為一個虛擬的表
在通常的子查詢中,子查詢是以巢狀的方式寫在
父查詢的WHERE、HAVING、FROM子句中,所以被
稱為巢狀子查詢。
• 巢狀子查詢的執行過程:
–1.子查詢首先執行一次;
–2.用來自子查詢的值確認或取消父查詢的候選行。
例:思考如何查詢比本部門平均薪水高的員工姓
名,薪水。
• 巢狀子查詢的寫法 SELECT empno,ename,sal
FROM emp e ,(SELECT deptno,avg(sal) avgsal
FROM emp
GROUP BY deptno) d
WHERE e.deptno =d.deptno
AND e.sal >d.avgsal;
相關子查詢:
問題分析的思路:
父查詢的候選行記錄 –1.取得父查詢第一條候選行記
員工編號 工資 部門編號 錄的sal和deptno;
7369 800 20
7499 1600 30 –
7521 1250 30 部門的平均工資;
7566 2975 20
7654 1250 30 –3.用第一步取得的sal和第二
7698 2850 30 步取得的平均工資作比較,如
7782 2450 10
7788 3000 20 果sal>平均工資,則第一條候
7839 5000 10 選行記錄被顯示;否則,不被
7844 1500 30
7876 1100 20 顯示;
7900 950 30
–4.依次取得父查詢中的第2行
7902 3000 20
7934 1300 10 到最後一行,重複執行1-3。
使用相關子查詢實現:
SELECT empno,ename, sal,deptno
FROM emp outer
WHERE sal > (SELECT AVG(sal)
FROM emp
WHERE deptno =
outer.deptno) ;
父查詢中的行每被處理一次,子查詢就執行一次
• 相關子查詢的執行過程:
–1.取得父查詢的候選行;
–2.用候選行被子查詢引用列的值執行子查詢;
–3.用來自子查詢的值確認或取消候選行;
–4.重複步驟1、2、3,直到父查詢中無剩餘的候選行。
GET
取來自父查詢的候選行
EXECUTE
用候選行值執行子查詢
USE
用子查詢的值確認或取消候選行
練習1
• 如下練習,使用相關子查詢完成
• 1.查詢比所在職位平均工資高的員工姓名,職位
SELECT ename,job
FROM emp e
WHERE sal>(SELECT AVG(sal) FROM emp WHERE job=e.job)
• 2.查詢工資為其部門最低工資的員工編號,姓名 ,工資。
SELECT empno, ename,sal
FROM emp e
WHERE sal=(SELECT MIN(sal) FROM emp WHERE deptno=e.deptno)
相關子查詢 :
---查詢所有部門名稱和人數
---------------分組函式
SELECT d.dname,COUNT (empno)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.dname
----------巢狀子查詢
SELECT d.dname, ce 人數
FROM (SELECT deptno,COUNT (empno) ce FROM emp GROUP BY deptno)c,dept d
WHERE c.deptno=d.deptno
------------相關子查詢
SELECT dname,(SELECT COUNT (empno) FROM emp WHERE deptno=d.deptno)
FROM dept d
查詢哪些員工是經理?
--------------
SELECT * FROM emp WHERE empno IN (SELECT DISTINCT mgr FROM emp)
相關子查詢
SELECT * FROM emp e
WHERE (SELECT COUNT(empno)FROM emp WHERE mgr =e.empno)>0
例:查詢至少調過2次崗位的員工編號,姓名,
崗位
SELECT e.empno, ename, e.job
FROM emp e
WHERE 2 <= (SELECT COUNT(*)
FROM emp_jobhistory
WHERE empno = e.empno);
練習2
• 如下練習,用相關子查詢完成
• 1.查詢所有僱員編號,名字和部門名字。
SELECT empno ,ename,(SELECT dname FROM dept WHERE deptno =e.deptno)
FROM emp e
• 2.查詢哪些員工是經理?
SELECT * FROM emp e
WHERE(SELECT COUNT (empno) FROM emp WHERE mgr=e.empno)>0
• 3.查詢哪些員工不是經理?
SELECT * FROM emp e
WHERE(SELECT COUNT (empno) FROM emp WHERE mgr=e.empno)>0
• 4.查詢每個部門工資最低的兩個員工編號,姓名,工資。
SELECT *
FROM emp e
WHERE (SELECT COUNT(empno)FROM emp WHERE
deptno=e.deptno AND sal<e.sal)<=1
EXISTS和NOT EXISTS操作符
• 例:查詢哪些人是經理?
SELECTename , job, sal, deptno
FROM emp e
WHERE EXISTS (SELECT '1'
FROM emp
WHERE mgr= e.empno);
–因為EXISTS子句中,並沒有確切記錄返回,只返回真或假。所以’1’只是佔位用,無實際意義。
例:查詢哪些人不是經理?
SELECT ename, job, sal, deptno
FROM emp e
WHERE NOT EXISTS (SELECT '1'
FROM emp
WHERE mgr= e.empno);
–NOT EXISTS操作符因為運算方法與NOT IN不同,只會返回TRUE或FALSE,不會返回空值,所以不需要考慮子查詢去除空值的問題。
練習3
• 如下練習,用exists或not exists完成
• 1.列出至少有一個僱員的所有部門名稱。
SELECT dname FROM dept d
WHERE EXISTS (SELECT '1' FROM emp WHERE deptno=d.deptno)
• 2.列出一個僱員都沒有的所有部門名稱。
SELECT dname FROM dept d
WHERE NOT EXISTS (SELECT'1' FROM emp WHERE deptno=d.deptno)//此處不能用count(empno)有返回值的來查詢
課後作業 :
• 如下練習,使用相關子查詢完成。
• 1.查詢薪水多於他所在部門平均薪水的僱員名字 ,部門號。
SELECT ename,deptno
FROM emp e
WHERE sal>(SELECT AVG(sal) FROM emp WHERE deptno=e.deptno)
• 2.查詢員工姓名和直接上級的名字。
SELECT ename,(SELECT ename FROM emp WHERE empno=e.mgr)
FROM emp e
• 3.查詢每個部門工資最高的員工姓名,工資。
SELECT *
FROM emp e
WHERE sal IN (SELECT MAX(sal)FROM emp GROUP BY deptno)--------------巢狀子查詢
或者
SELECT *
FROM emp e
WHERE (SELECT COUNT(empno) FROM emp WHERE deptno=e.deptno AND sal>e.sal)<=0 相關子查詢
• 4.查詢每個部門工資前兩名高的員工姓名,工資。
SELECT *
FROM emp e
WHERE (SELECT COUNT(empno)FROM emp WHERE
deptno=e.deptno AND sal>e.sal)<=1
----exists,not exists 跟相關子查詢一起使用
-----in,not in 跟巢狀子查詢一起用