1. 程式人生 > >第九章高階子查詢

第九章高階子查詢

第九章

巢狀子查詢:可以理解為一個虛擬的表

在通常的子查詢中,子查詢是以巢狀的方式寫在 

    父查詢的WHEREHAVINGFROM子句中,所以被 

    稱為巢狀子查詢。 

 • 巢狀子查詢的執行過程: 

      –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.取得父查詢第一條候選行記 

   員工編號  工資  部門編號                        錄的saldeptno; 

     7369       800        20 

     7499       1600       30          

2.根據取得的deptno,獲取該 

     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.重複步驟123,直到父查詢中無剩餘的候選行。 

                                     GET 

                            取來自父查詢的候選行 

                                  EXECUTE 

                            用候選行值執行子查詢 

                                    USE 

                      用子查詢的值確認或取消候選行 

練習

• 如下練習,使用相關子查詢完成 

• 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); 

練習

• 如下練習,用相關子查詢完成 

• 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

EXISTSNOT 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不同,只會返回TRUEFALSE,不會返回空值,所以不需要考慮子查詢去除空值的問題。 

練習

• 如下練習,用existsnot 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

----existsnot exists 跟相關子查詢一起使用

-----innot in  跟巢狀子查詢一起用