數(shù)據(jù)庫SQL中的表連接類型

數(shù)據(jù)庫中,如果用SQL語言進行多個表的查詢,就需要用到連接操作。這里對SQL中的連接類型進行簡單的介紹。本文內(nèi)容可能會涉及以下幾張表:

院系表:department(dept_name, building, budget);
課程表:course(course_id, title, dept_name, credits)
老師表:instructor(ID, name, dept_name, salary)
教學(xué)表:teaches(ID, course_id, sec_id, semester)
學(xué)生表:student(ID, name, dept_name, tot_cred)
選課表:takes(ID, course_id, sec_id, semester, year, grade)

1、多表查詢

如果要查詢所有教師的姓名、院系和院系所在的建筑,就需要用到多表查詢:

select name, instructor.dept_name, building
from instructor, department
where instructor.dept_name = department.dept_name

可以這樣理解,該查詢在執(zhí)行時,首先將instructor表和department表中的所有的記錄做笛卡爾積,然后,根據(jù)where子句中指定的謂詞,對笛卡爾乘積的結(jié)果進行篩選,最后得到查詢結(jié)果。

然而,實際中,該查詢不會按照這個步驟執(zhí)行,數(shù)據(jù)庫會(盡可能地)只產(chǎn)生滿足where子句謂詞的笛卡爾積元素來進行優(yōu)化執(zhí)行。

這是SQL種最基本的表連接形式。除此之外,SQL中還提供了關(guān)鍵字join,專門用于表連接查詢,這些連接可以分為內(nèi)連接(inner join)和外連接(outer join)兩種。外連接又分為左外連接(left outer join)、右外連接(right outer join)和全外連接(full outer join)。

2、自然連接

2.1 什么是自然連接

這里首先介紹自然連接,看下面的連接:

select name, instructor.dept_name, building
from instructor, department
where instructor.dept_name = department.dept_name

這里的連接謂詞是instructor.dept_name = department.dept_name,而這兩個表中名稱相同的字段只有dept_name。實際上,這是一種常見的情況。為此,SQL支持了一種叫做自然連接(natural join)的運算。

自然連接只取出兩張表的笛卡爾乘積中,那些在兩個表中都出現(xiàn)的字段上取值相同的結(jié)果。比如:

select name, instructor.dept_name, building
from instructor natural join department

這個例子中,只會取出instructor表和department表笛卡爾乘積結(jié)果中,那些instructor.dept_name和department.dept_name相等的記錄,作為連接的結(jié)果。因為dept_name是唯一的兩張表中都出現(xiàn)的字段(如果兩張表還有其他相同的字段,那么查詢結(jié)果中來自不同表的這些字段也都必須相等)。

2.2 自然連接注意

除了只關(guān)注兩個表中的相同字段,自然連接還有兩個地方需要注意:

  • 連接結(jié)果中,對于兩張表中都有的字段,只出現(xiàn)一次。

  • 字段出現(xiàn)的順序

    先是兩張表中都有的字段,然后是只出現(xiàn)在第一張表中的字段,最后是只出現(xiàn)在第二張表中的字段。

2.3 自然連接運算的結(jié)果是關(guān)系

關(guān)系數(shù)據(jù)庫中,關(guān)系就是表,表就代表關(guān)系。這里,自然連接運算的結(jié)果是關(guān)系,可以理解為自然連接的結(jié)果也是一張表。例子,查詢所有教師的名字,以及他們教授的課程名稱。

select name, title
from instructor natural join teaches, course
where teaches.course_id = course.course_id

這個例子中,先將instructor表和teaches表進行自然連接,由于得到的結(jié)果也是一個關(guān)系(表),所以也可以將該結(jié)果和course表連接。注意,這里的teaches.course_id是自然連接結(jié)果中的course_id字段,因為它是來自teaches表,所以用teaches.course_id標識。

2.4 using子句

看上面的連接語句,似乎可以寫成:

select name, title
from instructor natural join teaches natural join course

其實,前一個自然連接的結(jié)果包括字段(ID, name, dept_name, salary, course_id, sec_id),而course表包含的字段(course_id, title, dept_name, credits)。兩者的公共字段除了course_id之外,還有dept_name。所以,該SQL實際上相當于:

select name, title
from instructor natural join teaches, course
where teaches.course_id = course.course_id and teaches.dept_name = course.dept_name

為了避免不必要的相等屬性帶來的問題,同時發(fā)揚自然連接的優(yōu)點,SQL中提供了using子句來允許用戶指定哪些字段相等。例如,上面的SQL就相當于:

select name, title
from instructor natural join teaches natural join course using (course_id, dept_name)

當然,using子句中也可以是單個字段,如:

select name, title
from instructor natural join teaches natural join course using (course_id)

2.5 on子句

on子句允許在參與連接的關(guān)系上指定通用的謂詞,這個謂詞的寫法和where子句謂詞類似。和using子句一樣,on子句出現(xiàn)在連接表達式的末尾。下面是一個例子:

select *
from student join takes on student.ID = takes.ID

這里的意思是連接student表和takes表中,ID字段值相同的記錄。功能上和下面的腳本類似:

select *
from student natural join takes

兩者之間的區(qū)別就在于前者結(jié)果中ID屬性出現(xiàn)兩次,一次來自student,一次來自takes;而后者結(jié)果中ID屬性只出現(xiàn)一次,因為是自然連接。

on條件可以表示任何的SQL謂詞,因此使用on條件的連接表達式可以表示比自然連接更加復(fù)雜的連接條件。功能上,上面帶on子句的連接等價于:

select *
from student, takes
where student.ID = takes.ID

因此,可以將on子句中的謂詞移到where子句中,但這并不是說on子句是多余的,使用on子句有以下優(yōu)點:

  • 在外連接中,on子句和where子句的表現(xiàn)不同(后文介紹)。
  • 在on子句中指定連接條件,在where子句中出現(xiàn)其它的連接條件,這樣的SQL可讀性更好。

3、外連接

3.1 外連接介紹

看如下查詢:

select *
from student natural join takes

可以查詢出學(xué)生信息和每個學(xué)生的選課信息。但是,這里有個問題,如果有一名學(xué)生Snow沒有選任何課程,那么他不會出現(xiàn)在查詢結(jié)果中。為了避免參與連接的一個或兩個表中的某些記錄以這種方式“丟失”,SQL提供了外連接操作。通過在結(jié)果中創(chuàng)建包含空值記錄的方式,保留那些在連接中“丟失”的記錄。

SQL中的外連接有三種形式:

  • 左外連接(left outer join)
    保證出現(xiàn)在連接操作左邊的表記錄不“丟失”
  • 右外連接(right outer join)
    保證出現(xiàn)在連接操作右邊的表記錄不“丟失”
  • 全外連接(full outer join)
    保證出現(xiàn)在連接操作兩邊的表記錄都不“丟失”

比如,上面的例子中,為了保證學(xué)生記錄不丟失,可以采用左外連接:

select *
from student natural left join takes

這樣,查詢結(jié)果中就會多一條記錄,該記錄中來自student表中的字段就是student表中Snow記錄的值,而來自takes表中的字段都為null。

3.2 利用外連接查詢“丟失”的記錄

這樣,利用外連接,可以查詢出一門課都沒有選的學(xué)生:

select ID
from student natural left join takes
where course_id is null

注意:判斷是否為空用的是is null

3.3 左外連接和右外連接是對稱的

不難理解,如下的兩個連接基本等價:

select *
from student natural left join takes
基本等價于
select *
from takes natural left join student

這里,基本等價的意思是說,結(jié)果中屬性出現(xiàn)的順序會不同。

3.4 on子句和外連接

on子句也可以和外連接一起使用,下面兩個查詢的功能基本相同(除了結(jié)果中ID字段出現(xiàn)的次數(shù)):

select *
from student left outer join takes on student.ID = takes.ID
基本等價于
select *
from student left natural join takes

如前所述,外連接中on子句的表現(xiàn)和where子句不同,因為外連接只為結(jié)果集中沒有出現(xiàn)的記錄補上空值并插入結(jié)果集,on子句是外連接聲明的一部分。但where子句卻不是,where子句中的謂詞作用于外連接的結(jié)果,用來對外連接的結(jié)果進行篩選。看下面的查詢:

select *
from student left outer join takes on true
where student.ID = takes.ID

在這個查詢中,由于外連接中on子句的謂詞用的是true,所以student和takes表進行外連接實際上相當于做了笛卡爾積,在該外連接的結(jié)果中,包含所有來自兩個表的記錄,所以,不會向連接結(jié)果中補充空值記錄。而where子句只篩選出外連接結(jié)果中滿足謂詞條件的記錄。這樣,學(xué)生Snow這樣的記錄就不會出現(xiàn)在最后的結(jié)果中。這就是外連接中on和where的區(qū)別。

4、內(nèi)連接

區(qū)別于上面提到的外連接,SQL把一般的連接稱作內(nèi)連接(inner join)。而關(guān)鍵字inner是可選的,如果join子句中沒有outer前綴,那么默認的連接類型就是inner join。

select *
from student join takes using(ID)
等價于
select *
from student inner join takes using(ID)

類似地,natural join等價于natural inner join。

5、總結(jié)

實際上,內(nèi)連接和外連接可以歸納為連接的類型,而natural、on子句和using子句可以歸納為連接的條件。如下表:

連接類型 連接條件
inner join natural
left outer join on子句
right outer join using子句
full outer join ...

任意的連接類型可以和任意的連接條件,進行組合,來滿足連接查詢需求。

參考

《數(shù)據(jù)庫系統(tǒng)概念》 機械工業(yè)出版社 Abraham Silberschatz, Henry F. Korth, S. Sudarshan 楊冬青, 李紅燕, 唐世渭等譯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

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