1.子查詢回顧
SELECT select_list
FROM table
WHERE expr operator(SELECT select_list
FROM table);
例1:查詢emp表,顯示薪水大於平均薪水的僱員信息
SELECT *
FROM emp
WHERE sal>(SELECT AVG(sal)
FROM emp);
例2:顯示僱員的細節信息,要求這些僱員的經理和部門與僱員號爲7521或7698是相同的,但不包括empno爲7521或7698的僱員信息
SELECT *
FROM emp
WHERE (mgr,deptno) IN(SELECT mgr,deptno
FROM emp
WHERE empno IN(7521,7698))
AND empno NOT IN(7521,7698);
例3:顯示與薪水大於2900元的僱員相同部門、相同工作類型的其他僱員信息
SELECT *
FROM emp
WHERE (deptno,job) IN(SELECT deptno,job
FROM emp
WHERE sal>2900)
AND sal<=2900;
例4:顯示與薪水大於2900元的僱員相同部門、相同工作類型的其他僱員信息(在FROM子句中使用子查詢)
SELECT *
FROM emp e,(SELECT deptno,job,sal
FROM emp
WHERE sal>2900) s
WHERE e.deptno=s.deptno
AND e.job=s.job
AND e.sal!=s.sal;
2.相關子查詢
1)相關子查詢是一種讀表中每一行並且依靠相關數據比較每行的值的方法,相關子查詢被用於row-by-row處理。對外查詢的每一行,每個子查詢被執行一次。
2)嵌套子查詢與相關子查詢
(1)嵌套子查詢的執行
-內查詢首先執行並且查找值
-外查詢用內查詢的值執行一次
(2)相關子查詢的執行
-用外查詢取得候選行
-用候選行的值執行內查詢
-用來自內查詢的值確認或取消候選行
-重複直到無剩餘的候選行
SELECT column1,column2,...
FROM table1 outer
WHERE column1 operator(SELECT column1,column2
FROM table2
WHERE expr1=outer.expr2)
例:找出所有的僱員,他們掙的薪水高於該部門的平均薪水
SELECT ename,deptno,sal
FROM emp outer
WHERE sal>(SELECT AVG(sal)
FROM emp
WHERE deptno=outer.deptno);
結果:
ENAME DEPTNO SAL
ALLEN 30 1600
JONES 20 2975
BLAKE 30 2850
SCOTT 20 3000
KING 10 5000
FORD 20 3000
小王 10 3000
3.EXISTS操作
EXISTS操作對在子查詢的結果集中存在的行進行檢驗:
1)如果一個子查詢行值被找到:
-在內查詢中的搜索不再繼續
-條件被標記爲TRUE
2)如果一個子查詢行值未找到
-條件被標記爲FALSE
-在內查詢中的搜索繼續
例:查找至少有一個僱員的經理信息
SELECT *
FROM emp outer
WHERE EXISTS(SELECT 'X'
FROM emp
WHERE mgr=outer.empno);
結果:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
7566 JONES MANAGER 7839 02-4月 -81 2975 20
7698 BLAKE MANAGER 7839 01-5月 -81 2850 30
7782 CLARK MANAGER 7839 09-6月 -81 2450 10
7788 SCOTT ANALYST 7566 19-4月 -87 3000 20
7839 KING PRESIDENT 17-11月-81 5000 10
7902 FORD ANALYST 7566 03-12月-81 3000 20
4.NOT EXISTS操作
例:查找部門編號不在僱員表中的部門信息
SELECT *
FROM dept
WHERE NOT EXISTS(SELECT *
FROM emp
WHERE emp.deptno=dept.deptno);
5.相關UPDATE
-用一個相關子查詢來更新一個表中的行,該表中的行基於另一個表中的行
UPDATE table1 alias1
SET column=(SELECT expression
FROM table2 alias2
WHERE alias1.column=alias2.column);
例:1.在僱員表中增加部門名稱列
ALTER TABLE emp
ADD (dname VARCHAR2(14));
2.使用部門表中的部門名稱更新僱員表中的部門名稱
UPDATE emp e
SET dname=(SELECT dname
FROM dept d
WHERE e.deptno=d.deptno);
6.相關delete
-用一個相關子查詢來刪除一個表中的行,該表中的行基於另一個表中的行
DELETE FROM table1 alias1
WHERE column operator(SELECT expression
FROM table2 alias2
WHERE alias1.column=alias2.column);
例:用一個相關子查詢刪除emp表中的數據,被刪除的數據是emp表和job_history表中有相同empno列值的數據
DELETE FROM emp e
WHERE empno IN (SELECT empno
FROM job_history
WHERE empno=e.empno);
7.WITH子句
1)當一個查詢塊在一個複雜的查詢中出現多次時,使用WITH子句,能夠用在SELECT語句中使用相同查詢塊
2)WITH子句取回查詢塊的結果,並且將它存在用戶的臨時表空間中
3)WITH子句可以改善性能
例:用WITH子句,寫一個查詢來顯示部門名稱和該部門的合計薪水,那些人的合計薪水高於各部門的平均薪水
WITH
dept_costs AS(
SELECT d.dname,SUM(e.sal) AS dept_total
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.dname),
avg_costs AS(
SELECT SUM(dept_total)/COUNT(*) AS dept_avg
FROM dept_costs)
SELECT *
FROM dept_costs
WHERE dept_total>(SELECT dept_avg
FROM avg_costs)
ORDER BY dname;
結果:
DNAME DEPT_TOTAL
ACCOUNTING 11750
RESEARCH 14075
練習
1.顯示變換過至少兩次工作的僱員的詳細情況(emp和job_history)
2.寫一個子查詢顯示任何一個其部門號和薪水都與任何掙佣金的僱員的部門號和薪水相匹配的僱員的名字、部門號和薪水
SELECT ename,deptno,sal
FROM emp
WHERE (deptno,sal) IN(SELECT deptno,sal
FROM emp
WHERE comm IS NOT NULL);
3.顯示任何其薪水和佣金與任何位於loc爲CHICAGO的僱員薪水和佣金相匹配的僱員的名字、部門名和薪水
SELECT ename, dname, sal
FROM emp e, dept d
WHERE e.deptno = d.deptno
AND (sal, NVL(comm,0)) IN (SELECT sal, NVL(comm,0)
FROM emp e, dept d
WHERE e.deptno = d.deptno
AND d.loc = 'CHICAGO');
4.創建一個查詢來顯示所有其薪水和佣金與SCOTT相同的僱員的名字、受僱日期和薪水(不顯示SCOTT的信息)
SELECT ename,hiredate,sal
FROM emp
WHERE (sal,NVL(comm,0)) IN (SELECT sal,NVL(comm,0)
FROM emp
WHERE ename='SCOTT')
AND ename!='SCOTT';
5.創建一個查詢來顯示那些所掙薪水高於所有經理(job='MANAGER')的僱員的名字、工作崗位和薪水。依據薪水從最高到最低排序結果集
SELECT ename,job,sal
FROM emp
WHERE sal>ALL (SELECT sal
FROM emp
WHERE job='MANAGER')
ORDER BY sal DESC;
6.顯示那些住在城市名字以N開頭的城市的僱員的ID、名字和部門號
SELECT empno,ename,deptno
FROM emp
WHERE deptno IN(SELECT deptno
FROM dept
WHERE loc LIKE 'N%');
7.寫一個查詢來查找所有其薪水多於他所在部門的平均薪水的僱員,顯示名字、部門號和部門的平均薪水,按平均薪水排序
SELECT ename,e.deptno,sal,a.avg
FROM emp e,(SELECT deptno,AVG(sal) avg
FROM emp
GROUP BY deptno) a
WHERE e.deptno=a.deptno
AND e.sal>a.avg
ORDER BY a.avg;
8.寫一個查詢顯示所掙薪水低於他們所在的部門平均薪水的僱員名
SELECT ename
FROM emp outer
WHERE sal< (SELECT AVG(sal)
FROM emp inner
WHERE deptno = outer.deptno);
或:
SELECT ename
FROM emp outer
WHERE outer.sal< (SELECT AVG(inner.sal)
FROM emp inner
WHERE inner.deptno = outer.deptno);
9.查找所有不是管理人員的僱員(僱員編號不在經理編號列的僱員)
SELECT *
FROM emp
WHERE empno NOT IN(SELECT mgr
FROM emp
WHERE mgr IS NOT NULL);
或:
SELECT *
FROM emp outer
WHERE NOT EXISTS(SELECT 'X'
FROM emp
WHERE mgr=outer.empno);
或:
SELECT *
FROM emp
WHERE empno NOT IN (SELECT NVL(mgr,0)
FROM emp);