SQL JOIN 的使用

由於工作需要,現在也開始寫一些複雜一點的 sql 了。由於之前對於 joinwhere 關鍵字的使用一直有疑惑,故寫一篇文章整理一下,算是對 sql 中各種表聯結使用的一個總結。

SQL JOIN 的作用

sql 關鍵字 unionintersect 屬於以行方向爲單位的集合運算,進行這些集合運算時,會導致記錄行數的增加或減少。
關鍵字 join 則是屬於列方向的運算,將其他表中的列添加過來。我們稱這種操作爲聯結。
sql 聯結根據其用途可以分爲多種,這裏主要講述內聯結與外聯結。

INNER JOIN

內聯結,inner join,是使用最廣泛的聯結運算。我們以例子來說明內聯結的含義。

student 表結構與記錄以下:

student_id student_name
1 Leo
2 Lee
3 Hao

score 表結構與記錄以下:

student_id student_score
1 89
2 95

可以看到 student_id 列存在於 student 表和 score 表,其他列則只存在於一張表。可以將 student_id 列作爲橋樑,將兩表滿足同樣條件的列彙集到同一結果之中,這就是聯結運算。

可以看到,學生 Leo 的 id 爲 1,分數在 score 表,Leo 的分數爲 89 分。學生 Lee 的 id 爲 2,分數爲 95。學生 Hao 的 id 爲 3,但 score 表中沒有 Hao 的分數。

使用 inner joinstudent 表和 score 表進行聯結,sql 以下所示:

select st.student_id, st.student_name, sc.student_score
from student st
       inner join score sc on st.student_id = sc.student_id;

執行 sql 結果如下所示。

student_id student_name student_score
1 Leo 89
2 Lee 95

關於 inner join 的使用,有幾點需要注意的。

  • from 子句

from 子句使用 inner join ,將兩張表聯結起來。

  • on 子句

on 子句是聯結的條件,例如我們使用 student_id 作爲聯結條件:

on st.student_id = sc.student_id

  • select 子句

select 子句用於指定提取哪些列。

  • 與 where 子句結合

如果我們只想看查 student_id 爲 1 的情況,可以繼續使用 where 子句。

select st.student_id, st.student_name, sc.student_score
from student st
       inner join score sc on st.student_id = SC.student_id
where st.student_id = 1;

執行結果以下:

student_id student_name student_score
1 Leo 89

OUTER JOIN

外聯結,outer join,與內聯結一樣,也是通過 on 子句將兩張表聯結起來,只是結果有所不同。

爲了說明外聯結與內聯結的不同,我們將上面內聯結的例子轉換成外聯結,看下執行結果。

select st.student_id, st.student_name, sc.student_score
from student st
       left outer join score sc on st.student_id = sc.student_id;

執行結果如下表所示:

student_id student_name student_score
1 Leo 89
2 Lee 95
3 Hao
  • 外聯結選取出單張表全部記錄

與內聯結相比,外聯結的不同點在於結果的行數不一樣。內聯結執行結果有 2 條記錄,外聯結卻有 3 條記錄,增加的 1 條記錄是 student_id 爲 3 的學生 Hao。雖然 score 表並沒 student_id 爲 3 的成績,但執行結果仍然把這條記錄提取出來了。在實際應用中,如果我們想生成固定行數的數據時,就需要使用外聯結。

內聯結只會提取同時存在於兩張表中的數據,因此 Hao 學生記錄並不會出現。對於外聯結來說,只要數據存在於某一張表中,就能夠提取出來。

同時我們也看到,由於 score 表中並沒有 Hao 學生的成績,所以執行結果該字段爲 null。

  • 外聯結可以指定主表

外聯結可以指定哪張表爲主表,查詢結果會包含主表的所有記錄。使用 left 時 from 子句中寫在左側的表是主表,使用 right 時右側的表是主表。上述外聯結代碼使用 left ,因此左側的 student 表是主表。

我們也可以使用 right 對代碼進行改寫,效果完全一樣。

select st.student_id, st.student_name, sc.student_score
from score sc
       right outer join student st on st.student_id = sc.student_id;

至於使用 left 或者 right,使用哪一個都可以,通常來說,使用 left 的情況多一些。

CROSS JOIN

交叉聯結,cross join,是指對聯結的表進行笛卡爾積運算。

我們對 student 表和 score 表進行交叉聯結:

select st.student_id, st.student_name, sc.student_id, sc.student_score
from student st
       cross join score sc;

查詢結果如下:

student_id student_name student_id student_score
1 Leo 1 89
2 Lee 1 89
3 Hao 1 89
1 Leo 2 95
2 Lee 2 95
3 Hao 2 95

進行交叉聯結時,無法使用內聯結和外聯結中所使用的 on 子句,這是因爲交叉聯結是對兩張表中的全部記錄進行交叉組合,結果記錄數是兩張表中行數的乘積。student 表包含 3 條記錄,score 表包含 2 條記錄,故交叉聯結結果包含 3 * 2 = 6 條記錄。

內聯結是交叉聯結的一部分,“內”可以理解爲“包含在交叉聯結結果中的部分”。相反,外聯結的“外”可以理解爲“交叉聯結結果之外的部分”。

在實際應用中,交叉聯結使用較少。一是其結果沒有實用價值,二是由於結果太多,需要花費大量的運算時間。

過時的語法

上述 sql 代碼中,我們使用 inner joinouter join 等聯結關鍵字符合 sql 標準,但實際開發中,卻經常會碰到使用 where 關鍵字來實現聯結。

將上面我們實現內聯結的 sql 代碼替換成使用 where 來實現:

select st.student_id, st.student_name, sc.student_score
from student st, score sc
where st.student_id = sc.student_id and st.student_id = 1;

執行結果以下:

student_id student_name student_score
1 Leo 89

這樣的書寫方式的查詢結果與標準語法的查詢結果相同,但這種語法不僅已過時,還存在其他問題:

  • 難以判斷是內聯結還是外聯結
  • 難以判斷哪部分是聯結條件,哪部分是用來選取記錄的限制條件
  • 可能在將來不能使用

雖然不建議使用過時的語法,但我們仍然需要具備閱讀這些過時語法代碼的能力 ?

參考資料

  • SQL 基礎教程,第 2 版,MICK 著,孫淼,羅勇譯
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章