第七講 SQL語(yǔ)言之復(fù)雜查詢

-- 子查詢: 出現(xiàn)在Where子句中的Select語(yǔ)句被稱為子查詢(subquery)
-- 三種類型的子查詢: (NOT) IN, θ-Some / θ-All, (Not) Exists

-- 表達(dá)式 [not] in (子查詢)
-- 示例: 列出張三, 王三同學(xué)的所有信息 
Select Sname from Student 
  where Sname in ('SanZhang', 'SanWang');
-- 列出選修了001號(hào)課程的學(xué)生的學(xué)號(hào)和姓名
-- 不用子查詢
select SC.`S#`, Student.Sname from SC, Student 
  where `C#` in ('001') and SC.`S#`=Student.`S#`;
-- 使用子查詢( 先找出選了001課程的學(xué)號(hào), 然后再?gòu)腟tudent表中找學(xué)號(hào)對(duì)應(yīng)的姓名 )
select `S#`, `Sname` from Student 
  where `S#` in (select `S#` from SC where `C#`='001');
-- 求既學(xué)過(guò)001號(hào)課程又學(xué)過(guò)002號(hào)課程的學(xué)生學(xué)號(hào)
select `S#` from SC 
  where `C#`='001' and
    `S#` in (select `S#` from SC where `C#`='002');
-- 列出沒(méi)有學(xué)過(guò)李明老師講授課程的所有同學(xué)的姓名
-- 我寫的
select distinct Sname from Student S, SC, Course C 
  where S.`S#`=SC.`S#` and SC.`C#`=C.`C#` and C.`T#` not in 
    (select `T#` from Teacher where Tname='MingLi');
-- PPT給的(小問(wèn)題, 選出來(lái)的人有重復(fù)的, 應(yīng)該加上distinct)(起別名, 簡(jiǎn)潔)
select Sname from Student 
  where `S#` not in (select `S#` from SC, Course C, Teacher T 
    where T.Tname='MingLi' and SC.`C#`=C.`C#` and T.`T#`=C.`T#`);
-- 查詢嵌套, 分外層查詢和內(nèi)層查詢
-- 內(nèi)層查詢與外層查詢無(wú)關(guān), 為非相關(guān)子查詢, 有關(guān)就是相關(guān)子查詢(需要用到外層查詢的相關(guān)變量)

-- 相關(guān)子查詢
-- 示例: 求學(xué)過(guò)001號(hào)課程的同學(xué)的姓名
select Sname from Student Stud 
  where `S#` in (select `S#` from SC where `S#`=Stud.`S#` and `C#`='001');
-- 外層可以給內(nèi)層傳遞參數(shù), 反之不行, 也稱為變量的作用域原則

-- θ-Some / θ-All 子查詢
-- 基本語(yǔ)法:
-- 表達(dá)式 θ-Some (子查詢)
-- 表達(dá)式 θ-All (子查詢)
-- θ是比較運(yùn)算符: <, >, >=, <=, =, <>
-- 示例: 找出工資最低的教師的姓名
select Tname from Teacher
  where Salary <= all(select Salary from Teacher);

-- 找出001號(hào)課成績(jī)不是最高的所有學(xué)生的學(xué)號(hào)
-- 我寫的
select `S#` from SC 
  where `C#`='001' and Score < some(select Score from SC);
-- ppt的
select `S#` from SC
  where`C#`='001' and  Score < some(select Score from SC where `C#`='001');
-- 找出所有課程都不及格的學(xué)生的姓名(相關(guān)子查詢)
select Sname from Student 
  where 60 > all(select Score from SC where `S#`=Student.`S#`);
-- 人工查驗(yàn), 這條語(yǔ)句是不對(duì)的, 所有課程都不及格應(yīng)該只有一個(gè)人, 結(jié)果卻是有過(guò)掛科的
-- +----------+------+-------+
-- | S#       | C#   | Score |
-- +----------+------+-------+
-- | 98030101 | 001  |    92 |
-- | 98030101 | 002  |    85 |
-- | 98030101 | 003  |    88 |
-- | 98040202 | 002  |    90 |
-- | 98040202 | 003  |    80 |
-- | 98040202 | 001  |    55 |
-- | 98040203 | 003  |    56 |
-- | 98030102 | 001  |    54 |
-- | 98030102 | 002  |    85 |
-- | 98030102 | 003  |    48 |
-- +----------+------+-------+
-- +----------+----------+------+------+------+--------+-------+------+
-- | S#       | Sname    | Ssex | Sage | D#   | Sclass | Saddr | PID  |
-- +----------+----------+------+------+------+--------+-------+------+
-- | 98030203 | WuWang   | fe   |   19 | 04   | 980402 | NULL  | NULL |

-- 找出001號(hào)課成績(jī)最高的所有學(xué)生的學(xué)號(hào)
select `S#` from SC where `C#`='001' and Score >= all(select Score from SC where `C#`='001');
-- 找出98030101號(hào)同學(xué)成績(jī)最低的課程號(hào)
select `C#` from SC 
  where `S#`='98030101' and Score <= all(select Score from SC where `S#`='98030101');
-- 找出張三同學(xué)成績(jī)最低的課程號(hào)
-- 涉及相關(guān)子查詢
select `C#` from SC, Student S  
  where S.`S#`=SC.`S#` 
    and S.`Sname`='SanZhang' 
      and Score<=all(select Score from SC where S.`S#` = `S#`);

-- 等價(jià)性變換
-- 如下兩種表達(dá)相同
-- 表達(dá)式 = some (子查詢)
-- 表達(dá)式 in (子查詢)
-- 但是 not in 與 <>some 是不等價(jià)的
-- 與 not in等價(jià)的是 表達(dá)式 <> all

-- (NOT) EXISTS 子查詢
-- 基本語(yǔ)法
-- [not] exists (子查詢)
-- 語(yǔ)義: 子查詢結(jié)果中有無(wú)元組的存在(!!!選的是元組)
-- 示例: 檢索選修了趙三老師主講課程的所有同學(xué)的姓名(exists選出符合條件的元組, 而后再?gòu)闹羞x擇需要的字段)
select distinct Sname from Student 
  where exists( select * from SC, Course, Teacher where 
    SC.`C#`=Course.`C#` and SC.`S#`=Student.`S#` 
      and Course.`T#`=Teacher.`T#` and Tname='SanZhao');

-- 檢索學(xué)過(guò)001號(hào)教師主講的所有課程的所有同學(xué)的姓名
-- (似乎有問(wèn)題.....)(表示難以理解....)
select Sname from Student
  where not exists  -- 不存在
    (select * from Course where Course.`T#`='001' and not exists  -- 有一門001教師的課程, 沒(méi)學(xué)過(guò)
      (select * from SC where `S#`=Student.`S#` and `C#`=Course.`C#`));
-- 列出沒(méi)學(xué)過(guò)李明老師講授的任何一門課程的所有同學(xué)的姓名
select Sname from Student
  where not exists 
    (select * from Course, SC, Teacher 
      where Tname='MingLi' 
        and Course.`T#`=Teacher.`T#` 
          and Course.`C#`=SC.`C#` and `S#`=Student.`S#`);
-- 列出至少學(xué)過(guò)98030101號(hào)同學(xué)學(xué)過(guò)所有課程的同學(xué)的學(xué)號(hào)
Select distinct `S#` from SC SC1 
  where not exists                                                          -- 不存在
    (select * from SC SC2 where SC2.`S#`='98030101' and                     -- 有一門課該同學(xué)沒(méi)學(xué)過(guò)
      not exists (select * from SC where `C#`=SC2.`C#` and `S#`=SC1.`S#`));

-- 結(jié)果計(jì)算
-- 示例: 求有差額(差額>0)的任意兩位教師的薪水差額
select T1.Tname as TR1 , T2.Tname as TR2, T1.Salary-T2.Salary from Teacher T1, Teacher T2 
  where T1.Salary > T2.Salary;
-- 示例: 依據(jù)學(xué)生年齡求學(xué)生的出生年份, 當(dāng)前是2015年
select Sname, 2015-Sage+1 as Syear from Student;

-- 聚集函數(shù)
-- SQL提供了5個(gè)作用在簡(jiǎn)單列值集合上的內(nèi)置聚集函數(shù)agfunc, 分別是:
-- count sum avg max min
-- 示例: 求教師的工資總和
select sum(Salary) from Teacher;
-- 求計(jì)算機(jī)系教師的工資總和
select sum(Salary) from Teacher as T, Dept as D  
  where T.`D#`=D.`D#` and D.Dname='computer';
-- 求數(shù)據(jù)庫(kù)課的平均成績(jī)
select avg(Score) from SC, Course 
  where Cname='database' and Course.`C#`=SC.`C#`;

-- 分組聚集和分組過(guò)濾(分組是SQL的亮點(diǎn))
-- group by 分組條件
-- 示例: 求每個(gè)學(xué)生的平均成績(jī)(以每個(gè)學(xué)生為一個(gè)組)
select `S#`, avg(Score) from SC group by `S#`;
-- 求每一門課程的平均成績(jī)
select C.Cname, avg(SC.Score) avg from SC, Course C 
  where SC.`C#`=C.`C#` group by SC.`C#`;
-- 求不及格課程超過(guò)兩門的同學(xué)的學(xué)號(hào)
select `S#` from SC where Score<60 and count(*)>2 group by `S#`;  -- 錯(cuò)誤示范
-- 上面是錯(cuò)誤的, 因?yàn)镾core<60選出來(lái)的是元組, 而count(*) 是對(duì)于某一列的判斷, 所以是不正確的(后面會(huì)講解正確的操作)

-- 分組過(guò)濾
-- having子句, 無(wú)分組, 不過(guò)濾. 該子句的前提是有g(shù)roup的支持
-- 示例: 求不及格課程超過(guò)兩門的同學(xué)的學(xué)號(hào)
select `S#` from SC where Score<60 group by `S#` having count(*)>2;
-- having 表示對(duì)元組進(jìn)行統(tǒng)計(jì), 統(tǒng)計(jì)需要滿足要求是大于2
-- 示例: 求有1人以上不及格的課程號(hào)
select `C#` from SC where Score<60 group by `C#` having count(*)>1;

--having 和where子句表達(dá)條件的區(qū)別
-- 每一行都要檢查where子句, having是對(duì)分組進(jìn)行檢查, having前提要有g(shù)roup by子句

-- 示例: 求兩門以上不及格課程同學(xué)的學(xué)號(hào)及其平均成績(jī)
select `S#`, avg(Score) from SC where Score < 60 group by `S#` having count(*)>1;
-- 這條語(yǔ)句求的是不及格成績(jī)的平均成績(jī), 我們一般要這個(gè)學(xué)生的成績(jī)的平均 所以不正確
-- 正解(先選出不及格成績(jī)大于1的同學(xué)的學(xué)號(hào), 然后再對(duì)這些學(xué)號(hào)分組, 然后求平均, 這樣就不會(huì)有歧義了)
select `S#`, avg(Score) from SC  
    where `S#` in  (select `S#` from SC where Score<60 group by `S#` having count(*)>1) 
        group by `S#`;

-- SQL語(yǔ)言: 并運(yùn)算 union, 交運(yùn)算 intersect, 差運(yùn)算 except
-- 基本語(yǔ)法:
-- 子查詢 {union [ALL] | intersect [ALL] | except [ALL] 子查詢}
-- 通常情況下自動(dòng)刪除重復(fù)元組: 不帶ALL. 若要保留重復(fù)的元祖, 則要帶ALL
-- 示例:
-- 學(xué)過(guò)002號(hào)課的同學(xué)或?qū)W過(guò)003號(hào)課的同學(xué)學(xué)號(hào)
select `S#` from SC where `C#`='002' union 
select `S#` from SC where `C#`='003';
-- 也可以這樣
select distinct `S#` from SC where `C#`='002' or `C#`='003';
-- 當(dāng)表不一樣時(shí), or就不好使了, 就得用union

-- 求既學(xué)過(guò)002號(hào)課, 又學(xué)過(guò)003號(hào)課的同學(xué)學(xué)號(hào)(mysql 不支持 該 關(guān)鍵字)
select `S#` from SC where `C#`='002' intersect
select `S#` from SC where `C#`='003';
-- 也可以不用intersect來(lái)進(jìn)行(intersect 并不是唯一可選的, 所以增加了sql語(yǔ)言的不唯一性)
select `S#` from SC 
  where `C#`='002' and `S#` in (select `S#` from SC where `C#` = '003');

-- 假定所有學(xué)生都有選課, 求沒(méi)學(xué)過(guò)002號(hào)課程的學(xué)生的學(xué)號(hào)
-- 錯(cuò)誤示范(一個(gè)學(xué)生只要有兩條選課記錄, 就必然包含在該合集里面)
select `S#` from SC where `C#` <> '002';
-- 可以寫成這樣(mysql中也沒(méi)有except關(guān)鍵字)
select distinct `S#` from SC except select `S#` from SC where `C#` = '002';
-- 也可以這樣
select distinct `S#` from SC SC1 
  where not exists  (select * from SC where `C#`='002' and `S#` = SC1.`S#`);
-- 這說(shuō)明except也并沒(méi)有增強(qiáng)sql的表達(dá)能力了,
-- 沒(méi)有except, sql也可以用其他的方式表達(dá)同樣的查詢需求, 表達(dá)更簡(jiǎn)單, 但是增加了sql語(yǔ)言的不唯一性.

-- 空值處理
-- 示例: 找出年齡為空的學(xué)生的姓名
select Sname from Student where Sage is null;
-- mysql中空值的計(jì)算
-- count(*)包含null項(xiàng), count(具體列名) 忽略null項(xiàng); count(null)為0
-- avg, max, min, sum對(duì)null計(jì)算時(shí)全部忽略, 如果AVG(null)... 那么值為0
-- group by 對(duì)于null, 會(huì)單獨(dú)將其作為一項(xiàng)置于頂部, distinct類似

-- 內(nèi)連接, 外連接
-- 連接類型(四選一)
-- inner join
-- left outer join
-- right outer join
-- full outer join
-- 連接條件(三選一)
-- natural
-- on <連接條件>
-- using (col1, col2, ..., coln)
-- 錯(cuò)誤示例: 求所有教師的任課情況并按教師號(hào)排序(沒(méi)有任課的教師也需列在表中)
select Teacher.`T#`, Tname, Cname from Teacher 
  inner join Course on Teacher.`T#`=Course.`T#` order by Teacher.`T#`;
-- 上面丟失了一些老師的信息
-- 應(yīng)該使用左外連接(因?yàn)橐A魶](méi)有任課的老師也在列表之中)
select Teacher.`T#`, Tname, Cname from Teacher
  left outer join Course on Teacher.`T#`=Course.`T#` order by Teacher.`T#`;

-- 視圖
-- 示例: 定義一個(gè)視圖CompStud為計(jì)算機(jī)系的學(xué)生, 通過(guò)該視圖可以將Student表中其他系的學(xué)生屏蔽掉
create view CompStud as
  (select * from Student where `D#` in 
    (select `D#` from Dept where Dname='computer'));
-- 示例: 定義一個(gè)視圖Teach為教師任課的情況, 把Teacher表中的個(gè)人隱私方面的信息, 如工資等屏蔽掉, 僅反映其教哪門課及學(xué)分等
create view Teach 
  as ( select T.Tname, C.Cname, Cred from Teacher T, Course C where T.`T#`=C.`T#`);
-- 使用視圖的時(shí)候就像使用table一樣的去使用

-- 對(duì)視圖的更新(注意哪些視圖是可更新的, 哪些是不可更新的)
-- 如果視圖Select目標(biāo)列包含聚集函數(shù), 
-- Select子句使用unique或distinct,
-- 包含group by子句,
-- 包括算術(shù)表達(dá)式計(jì)算出來(lái)的列,
-- 由單個(gè)表的列構(gòu)成, 但并沒(méi)有包括主鍵, 則都 不能更新

-- 對(duì)于由單一Table子集構(gòu)成的視圖, 即如果視圖是從單個(gè)基本表使用選擇, 投影操作導(dǎo)出的, 并且包含了基本表的主鍵, 則可以更新

-- 撤銷視圖
drop view view_name;
-- 示例: 撤銷視圖 Teach
drop view Teach;



數(shù)據(jù)庫(kù)系統(tǒng)學(xué)習(xí)筆記

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市陌僵,隨后出現(xiàn)的幾起案子练链,更是在濱河造成了極大的恐慌瑰排,老刑警劉巖传泊,帶你破解...
    沈念sama閱讀 212,222評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件料仗,死亡現(xiàn)場(chǎng)離奇詭異状婶,居然都是意外死亡意敛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門膛虫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)草姻,“玉大人,你說(shuō)我怎么就攤上這事稍刀×枚溃” “怎么了?”我有些...
    開封第一講書人閱讀 157,720評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)综膀。 經(jīng)常有香客問(wèn)我澳迫,道長(zhǎng),這世上最難降的妖魔是什么剧劝? 我笑而不...
    開封第一講書人閱讀 56,568評(píng)論 1 284
  • 正文 為了忘掉前任纲刀,我火速辦了婚禮,結(jié)果婚禮上担平,老公的妹妹穿的比我還像新娘示绊。我一直安慰自己,他們只是感情好暂论,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評(píng)論 6 386
  • 文/花漫 我一把揭開白布面褐。 她就那樣靜靜地躺著,像睡著了一般取胎。 火紅的嫁衣襯著肌膚如雪展哭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,879評(píng)論 1 290
  • 那天闻蛀,我揣著相機(jī)與錄音匪傍,去河邊找鬼。 笑死觉痛,一個(gè)胖子當(dāng)著我的面吹牛役衡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播薪棒,決...
    沈念sama閱讀 39,028評(píng)論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼手蝎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了俐芯?” 一聲冷哼從身側(cè)響起棵介,我...
    開封第一講書人閱讀 37,773評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吧史,沒(méi)想到半個(gè)月后邮辽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,220評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贸营,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評(píng)論 2 327
  • 正文 我和宋清朗相戀三年吨述,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莽使。...
    茶點(diǎn)故事閱讀 38,697評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锐极,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芳肌,到底是詐尸還是另有隱情灵再,我是刑警寧澤肋层,帶...
    沈念sama閱讀 34,360評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站翎迁,受9級(jí)特大地震影響栋猖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜汪榔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評(píng)論 3 315
  • 文/蒙蒙 一蒲拉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痴腌,春花似錦雌团、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至剥悟,卻和暖如春灵寺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背区岗。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工略板, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人慈缔。 一個(gè)月前我還...
    沈念sama閱讀 46,433評(píng)論 2 360
  • 正文 我出身青樓叮称,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胀糜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子颅拦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評(píng)論 2 350

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