/*
====================================================================================================
-- 非關聯子查詢:單行子查詢,多行子查詢
-- 非關聯子查詢就是位於SELECT、UPDATE、或DELETE語句中內部的查詢語句
--子查詢(內部查詢)在執行主查詢之前執行一次 (只執行1次), 然後主查詢(外部查詢)會使用該子查詢的結果 遍歷全部記錄
-- -- Notice:子查詢的結果有多個值,oracle會去掉重複的記錄,再將結果返回給主查詢
=====================================================================================================
*/
-- ===========單行子查詢================================================================================
-- 子查詢只返回一條記錄.單行子查詢 ,用 <> , < , >, <=, >= , = 操作
--在WHERE 子句中使用子查詢
select ename,job from emp where empno = (select empno from emp where mgr = 7902 );
--分析:
--1.先執行select empno from emp where mgr = 7902(只執行1次)得到查詢結果7369.
--2. 再執行外部查詢:select ename,job from emp where empno =7369. 得到最終結果.
--使用分組函數的子查詢
select ename,job,sal from emp where sal > (select avg(sal) from emp);
-- from 後面的子查詢
select ename, job from (select * from emp where empno = 7369);
--單行子查詢中的常見錯誤
--子查詢的結果返回多於一行
select empno,ename from emp where sal = (select sal from emp where deptno = 20); --error
--子查詢中不能包含ORDER BY子句,任何的排序在外部查詢中完成
select empno,ename from emp where sal > (select avg(sal) from emp order by empno); -- error
select empno,ename from emp where sal > (select avg(sal) from emp) order by empno; -- ok
--子查詢內部沒有返回行,如下語句可以正確執行,但沒有數據返回
select ename,job from emp where empno = (select empno from emp where mgr = 8000); --error未選定行
-- ===========多行子查詢================================================================================
--子查詢 結果返回多條記錄給外部查詢(同樣執行1次),外部查詢用in, any , all 處理
-- 外部查詢用in , any , all 處理之前必須用一個 =, <>, <, >, <= , >= 操作符.
--查詢每個部門中薪水最高的員工姓名
select empno,ename,job from empwhere sal in (select max(sal) from emp group by deptno);
--分析:
-- 1.執行select max(sal) from emp group by deptno ; 返回多條記錄.
-- 2.執行select empno,ename,job from emp where sal in ( 從1中返回的多條記錄進行一條一條的匹配 ) ;
--查詢每個部門中低於平均薪水的員工姓名 (any 任何一個)
select empno,ename,job from emp where sal < any (select avg(sal) from emp group by deptno);
/*
====================================================================================================
-- 關聯子查詢:單行子查詢,多行子查詢
---- 子查詢中使用了主查詢中的某些字段,主查詢每掃描一行都要執行一次子查詢
-- 關聯子查詢:(採用loop的方式進行)
-- 1.外部查詢得到一條記錄(從外部表中讀取數據) 並將其傳入到內部查詢
-- 2.內部查詢基於傳入的值執行
-- 3.內部查詢從其結果中把值傳回到外部查詢,
-- 外部查詢使用這些值來完成其處理,若符合條件,外部表的那條記錄就放入結果集中,
-- 否則放棄(表示該記錄不符合條件)
-- 4. 重複1-3 .直到把outer表中的所有記錄判斷一遍
=====================================================================================================
*/
--查詢工資高於同一部門的員工的部門號,姓名,工資
select deptno,ename,sal from emp outer where sal >(
select avg(sal)from emp inner where inner.deptno = outer.deptno);
--分析:1. 取出外部outer的全部記錄一條一條的傳遞給子查詢(作爲子查詢的條件)
-- 2.子查詢根據外部查詢的條件執行1次子查詢
-- 3.直到外部記錄全部遍歷完爲止,才返回最終的結果
-- 重點:主查詢每掃描一行都要執行一次子查詢
/*
====================================================================================================
-- Exists:用來檢查子查詢返回行的存在性
-- 執行過程:
-- 1.外部查詢得到一條記錄(從外部表中讀取數據) 並將其傳入到內部查詢
-- 2.對inner表依次掃描,若根據條件存在一條記錄與 outer表中的記錄匹配,立即停止掃描,
返回ture.立即停止掃描inner表.那麼該outer 表中的記錄放入結果集中,
若掃描了全部記錄,沒有任何一條記錄符合匹配條件,
返回false, outer表的記錄被過濾掉,不能出現在結果集中.
-- 3.重複步驟1-2.直至遍歷完outer表中所有的記錄
=====================================================================================================
*/
--查詢負責管理其它員工的員工記錄(使用exists),即是領導的員工
select empno,ename from emp outer where exists
(select empno from emp inner where inner.mgr = outer.empno);
--分析:
-- 1. 把outer表中的1行記錄的empno傳進子查詢select empno from emp inner where inner.mgr =xx中.
-- 2.子查詢進行全部數據的遍歷,檢查是否符合where條件的記錄
-- 3.如果存在,那麼就把outer表中的該條記錄放入結果集.
--4.不存在,outer表中的該條記錄 不放入結果集.
-- 5.重複 1.- 4步,直到遍歷完outer表中的全部記錄,生成最終的結果集
-- Notice:exists只關心子查詢有沒有結果,並不需要返回值,所以上述語句調整爲(返回常量):
select empno,ename from emp outer where exists
(select 1 from emp inner where inner.mgr = outer.empno);
--========= not Exists 用Exists執行過程一樣,not Exists表示子查詢沒有返回則把outer表放入結果集
--查詢不管理其它員工的職員(not exists),查詢不是領導的員工
select empno,ename from emp outer where not exists
(select empno from emp inner where inner.mgr = outer.empno)
--分析:
-- 1. 把outer表中的1行記錄的empno傳進子查詢select empno from emp inner where inner.mgr =xx中.
-- 2.子查詢進行全部數據的遍歷,檢查是否符合where條件的記錄
-- 3.如果 不 存在,那麼就把outer表中的該條記錄放入結果集.
--4.存在,outer表中的該條記錄 不放入結果集.
-- 5.重複 1.- 4步,直到遍歷完outer表中的全部記錄,生成最終的結果集
--EXISTS 和NOT EXISTS 與IN 和NOT IN 的比較
-- EXISTS與IN的不同:
-- EXISTS只檢查行的存在性,IN 要檢查實際值的存在性(一般情況下EXISTS的性能高於IN)
-- NOT EXISTS 和NOT IN
-- 當值列表中包含空值的情況下,NOT EXISTS 則返回true,而NOT IN 則返回false.
-- update 的子查詢
update emp set salary = (select avg(salary) from emp ) where deptno = 10;
-- delete的子查詢
delete from emp where salary > (select avg(salary) from emp);
筆記:group by ... having 子句的用法:
select sum(salary) from emp group by deptno having deptno > 10;
或者
select sum(salary) from emp group by deptno having sum(salary) > 5000 ;