【Oracle學(xué)習(xí)11】 子查詢和集合運算符

【Oracle學(xué)習(xí)11】 子查詢和集合運算符

子查詢

11.1 定義子查詢

子查詢:

  • 子查詢是嵌套在另一個SQL語句中的查詢.
  • 子查詢可以嵌套在SELECT,INSERT,UPDATE,DELETE或其它查詢內(nèi)的查詢摇锋。
  • 子查詢不能在GROUP By及Order By中。
  • 子查詢可以返回標量酝枢,也可以返回一組記錄。
  • 除關(guān)聯(lián)子查詢外硼被,子查詢都在嵌套查詢的外查詢之前就先執(zhí)行书蚪。
subquery
subquery
#部門及員工數(shù)量
select sysdate Today, (select count(*) from departments ) dept_cnt,
(select count(*) from employees) emp_cnt from dual;
#找出經(jīng)理員工
select last_name from employees where (employee_id in (select manager_id from employees));
#每個國家最高薪水
SQL>select max(salary),country_id from (select e.salary,department_id,l.country_id from employees e join departments d using (department_id) 
 join locations l using (location_id)) 
 group by country_id;
MAX(SALARY) COUN
----------- ----
      24000 US
      13000 CA
      10000 DE
      14000 UK

##子查詢位置

11.2 子查詢可以解決的問題

11.2.1 將子查詢的結(jié)果集用于比較

子查詢可以返回標量猛蔽,也可以返回一組記錄黄刚。 標量子查詢只返回一個值。

#找出低于平均薪水的員工
select avg(salary) from employees; --$6461
select last_name,salary from employees where salary < (select avg(salary) from employees) order by salary desc;
#返回一組記錄,找出有員工的部門
select department_name from departments where department_id in (select distinct(department_id ) from employees);
select d.department_id,count(*)  as cnt from departments d join employees on d.department_id = employees.department_id group by d.department_id;

11.2.2 星型轉(zhuǎn)換

oracle可允許START_TRANSFORMATION_ENABLED

#多表關(guān)聯(lián)的sql可改寫為星型SQL
select count(quantity_sold) from sales , products, cust_id where sales.xx = products.xx and ... ;
#星型SQL
select count(quantity_sold) from sales where prod_id in 
(select prod_id from products where prod_name='Comic Book Heroes') 
and cust_id in (select cust_id from customers where cust_city='Oxford');

11.2.3 生成對其執(zhí)行SELECT 語句的表

內(nèi)聯(lián)視圖:
FROM子句中的子查詢诫尽,叫稱為內(nèi)聯(lián)視圖(inline views)禀酱。

#查詢各國家的平均薪水
select avg(salary) ,country_id from 
(select salary,country_id from employees natural join departments natural join locations) group by country_id;
AVG(SALARY) COUN
----------- ----
       5640 US
       6000 CA
       8500 UK

11.2.4 生成投影值

select (select max(salary) from employees) * (select max(commission_pct) from employees) / 100  from dual;

11.2.5 生成傳遞給DML語句的行

insert into sales_hist select * from sales where date>sysdate-1;

update employees set salary = (select avg(salary) from employees) ; 

delete from departments where department_id not in (select department_id from employees where department_id is not null);

11.3 列舉子查詢的類型

子查詢可以分成a)單行子查詢 b)多行子查詢 c)關(guān)聯(lián)子查詢

subquery
單行子查詢
i多行子查詢
子查詢與Having

11.3.1 單行和多行子查詢

  • 在父查詢之前就需要執(zhí)行子查詢。
  • 適用于單行子查詢的運算符是=,>,>=,<,<=和<>牧嫉。 多行子查詢的比較運算符是IN,NOT IN,ANY和ALL剂跟。
錯誤示例
多行子查詢
多行子查詢
SQL>SELECT salary FROM   employees WHERE  job_id = 'IT_PROG';
    SALARY
----------
      9000
      6000
      4800
      4800
      4200
#salary < all 沒有大于4200元工資
SELECT employee_id, last_name, job_id, salary
FROM   employees
WHERE  salary < all
                    (SELECT salary
                     FROM   employees
                     WHERE  job_id = 'IT_PROG')
AND    job_id <> 'IT_PROG' order by salary;

#salary < ANY ??是指??
SQL>SELECT employee_id, last_name, job_id, salary
FROM   employees
WHERE  salary < ANY
                    (SELECT salary
                     FROM   employees
                     WHERE  job_id = 'IT_PROG')
AND    job_id <> 'IT_PROG';
多列名子查詢
Null Values in a Subquery
# 多列名子查詢
#找出各部門工資最少的人
SQL> SELECT first_name, min(salary), department_id FROM employees GROUP BY department_id  order by department_id;
ERROR at line 1:
ORA-00979: not a GROUP BY expression
#正確寫法如下:
SELECT min(salary), department_id FROM employees
       GROUP BY department_id order by department_id;
#
SQL> SELECT first_name, department_id, salary FROM employees
    WHERE (salary, department_id) IN
          (SELECT min(salary), department_id
           FROM employees
           GROUP BY department_id)
    ORDER BY department_id;

FIRST_NAME                               DEPARTMENT_ID     SALARY
---------------------------------------- ------------- ----------
Jennifer                                            10       4400
Pat                                                 20       6000
Karen                                               30       2500
Susan                                               40       6500
TJ                                                  50       2100
Diana                                               60       4200
Hermann                                             70      10000
Sundita                                             80       6100
Neena                                               90      17000
Lex                                                 90      17000
Luis                                               100       6900
William                                            110       8300

#Null Values in a Subquery。找出不是manager的員工酣藻,如下是錯誤的曹洽。
SELECT distinct manager_id FROM   employees; -- rownum=19 有一個null
SQL> SELECT emp.last_name FROM   employees emp
WHERE  emp.employee_id NOT IN
 (SELECT mgr.manager_id FROM   employees mgr);
no rows selected

#可以改寫為
SQL>SELECT emp.last_name,manager_id FROM   employees emp
WHERE  emp.employee_id NOT IN
(SELECT nvl(mgr.manager_id,0) FROM   employees mgr) order by manager_id ;    

11.3.2 關(guān)聯(lián)子查詢

關(guān)聯(lián)子查詢效率較差

#找出薪水少于部門平均薪水的所有員工.
select p.last_name ,p.department_id from employees p 
 where p.salary < (select avg(s.salary) from employees s where s.department_id = p.department_id );
LAST_NAME                                          DEPARTMENT_ID
-------------------------------------------------- -------------
OConnell                                                      50
Grant                                                         50
Fay                                                           20
Gietz                                                        110
...
#找出薪水大于'Taylor'的人
SQL> select last_name from employees where salary > (select salary from employees where last_name = 'Taylor') order by last_name;
ORA-01427: single-row subquery returns more than one row

改正方法1:
select last_name from employees where salary > all (select salary from employees where last_name = 'Taylor') order by last_name;

方法2:
select last_name from employees where salary >  (select max(salary) from employees where last_name = 'Taylor') order by last_name;

11.4 寫單行和多行子查詢

# 找平均薪水最高的工作
SQL>select job_title from jobs natural join employees group by job_title 
having avg(salary) = (select max(avg(salary)) from employees group by job_id);
JOB_TITLE
----------------------------------------------------------------------
President

11.4.1 使用Exists 條件

#EXISTS 存在一個或多個就返回True。
#有員工的部門.從外表中一條條取記錄辽剧,在子表中比較.
select department_name from departments d where exists (select * from employees e where d.department_id= e.department_id);
#沒有員工的部門
select department_name from departments d where not exists (select * from employees e where d.department_id= e.department_id);

11.4.2 子查詢的空結(jié)果

若子查詢有可能為空送淆,則需要避免使用not in ,因為這相當(dāng)于<>all怕轿。

#結(jié)果為空偷崩,因為子查詢會返回null
SQL> select last_name,employee_id,manager_id from employees where employee_id not in (select manager_id from employees);
no rows selected
改為。找出沒有經(jīng)理的員工
select last_name,employee_id,manager_id from employees where employee_id not in (select manager_id from employees where manager_id is not null); --rownum=50

#有經(jīng)理的員工
select last_name,employee_id,manager_id from employees where employee_id in (select manager_id from employees where manager_id is not null);

11.5 描述集合運算符

三種集合運算: UNION,INTERSECT 撞羽,MINUS阐斜。

  • UNION : 返回查詢合并,排序并刪除重復(fù)行诀紊。 多個結(jié)果集UNION谒出,結(jié)果會自動轉(zhuǎn)換為最高的精度。
  • UNION ALL: 返回查詢合并邻奠,不排序笤喳,不去重。
  • INTERSECT: 只返回同時出現(xiàn)在兩個查詢結(jié)果集中的行碌宴,排序這些行并刪除重復(fù)行杀狡。 求交集。
  • MINUS: 只返回第一個結(jié)果集中的行唧喉,并且這些行不能出現(xiàn)在第二個結(jié)果集中。 減集忍抽。
集合運算符

11.5.1 集合和維恩圖

集合運算要求:

  • 查詢結(jié)果集的列數(shù)必須相同八孝。 數(shù)據(jù)類型大致相同(即相同或者可隱式轉(zhuǎn)換)。
  • 集合運算可以有不同的名稱鸠项,再輸出結(jié)果用第一個查詢的名稱干跛。
  • UNION,MINUS,INTERSECT都會刪除重復(fù)的行記錄祟绊。
  • 會默認返回接所有列排序(從左到右)行楼入。 除非使用 NUNION ALL哥捕,則不會排序。
  • 集合運算符的優(yōu)先級相同嘉熊,以指定它們的順序應(yīng)用遥赚。
  • 集合中Order by 只能出現(xiàn)在結(jié)果集的最忍氣吞聲,不能出現(xiàn)在一個查詢中間阐肤。
集合運算原則
UNION
INTERSECT
MINUS
image.png
#UNION
SQL> select region_name from regions UNION select region_name from regions;
REGION_NAME
--------------------------------------------------
Americas
Asia
Europe
Middle East and Africa

#  UNION ALL如下將不排序
select region_name from regions UNION ALL select region_name from regions;

#INTERSECT
SQL> select region_name from regions INTERSECT (select region_name from regions where region_name like 'A%' );
REGION_NAME
--------------------------------------------------
Americas
Asia

#MINUS
SQL> select region_name from regions MINUS (select region_name from regions where region_name like 'A%' );
REGION_NAME
--------------------------------------------------
Europe
Middle East and Africa

SQL> select region_name from regions MINUS (select region_name from regions  );
no rows selected

#兩表列數(shù)對齊凫佛,可以使用TO_CHAR
SQL>SELECT location_id, department_name "Department", 
   TO_CHAR(NULL) "Warehouse location"  
FROM departments
UNION
SELECT location_id, TO_CHAR(NULL) "Department", 
   state_province
FROM locations;

11.6 使用集合運算符將多個查詢合并為一個查詢

#多個結(jié)果集UNION,結(jié)果會自動轉(zhuǎn)換為最高的精度孕惜。
#不同的結(jié)果集可以增加null列來運用
select name,tail_length,null from cats union all select name,null ,wingspan from birds;
select sysdate , null from dual union select null ,'zhang3' from dual;

11.7 返回行的順序

返回行的順序:

  • 不能在組成復(fù)合查詢的單個查詢中使用ORDER BY 子句
  • 可以在復(fù)合查詢的結(jié)尾添加ORDER BY 子愧薛,并指定列號或別名
  • UNION ALL 返回的行按它們在兩個源查詢中出現(xiàn)的順序排列
  • 非UNION ALL,依從左到右列的順序排序返回的行衫画。
order by

11.8 知識點回顧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毫炉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子削罩,更是在濱河造成了極大的恐慌瞄勾,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鲸郊,死亡現(xiàn)場離奇詭異丰榴,居然都是意外死亡,警方通過查閱死者的電腦和手機秆撮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門四濒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人职辨,你說我怎么就攤上這事盗蟆。” “怎么了舒裤?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵喳资,是天一觀的道長。 經(jīng)常有香客問我腾供,道長仆邓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任伴鳖,我火速辦了婚禮节值,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘榜聂。我一直安慰自己搞疗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布须肆。 她就那樣靜靜地躺著匿乃,像睡著了一般桩皿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上幢炸,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天泄隔,我揣著相機與錄音,去河邊找鬼阳懂。 笑死梅尤,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岩调。 我是一名探鬼主播巷燥,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼号枕!你這毒婦竟也來了缰揪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤葱淳,失蹤者是張志新(化名)和其女友劉穎钝腺,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赞厕,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡艳狐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了皿桑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毫目。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖诲侮,靈堂內(nèi)的尸體忽然破棺而出镀虐,到底是詐尸還是另有隱情,我是刑警寧澤沟绪,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布刮便,位于F島的核電站,受9級特大地震影響绽慈,放射性物質(zhì)發(fā)生泄漏恨旱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一坝疼、第九天 我趴在偏房一處隱蔽的房頂上張望搜贤。 院中可真熱鬧,春花似錦裙士、人聲如沸入客。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桌硫。三九已至,卻和暖如春啃炸,著一層夾襖步出監(jiān)牢的瞬間铆隘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工南用, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留膀钠,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓裹虫,卻偏偏與公主長得像肿嘲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子筑公,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容