SQL 中不同類型的表連接
1、簡介
在關系型數據庫中,join操作是將不同的表中的數據聯合在一起時非常通用的一種做法。首先讓我們看看join是如何操作的,然后我們探索一下當join和where語句同時存在的時候的執行順序問題,最后來談一談不同類型的join的順序問題。
2、建立初始的測試表結構(建表語句到這里下載)
表建立完之后,將會看到如下三個表。
我們將通過以上三個表來演示join操作。這三個表都是用來做演示的,所以我并沒有使用主鍵和外鍵。
3、表的笛卡爾乘積
一般情況下,我們使用兩個表中的相關字段進行join操作,例如,employee表中的DeptId字段對應于Department表中的DepId字段,通過這種方式進行join。
下面的一個例子是不使用關聯字段來做表的連接。這里TableA和TableB以笛卡爾乘積的方式連在了一起。笛卡爾乘積就是先從第一個表中取出一條記錄,和第二章表中的每一條記錄配合,然后再取出第二條記錄,同樣和第二張表的所有記錄配合,直至第一張表中的所有記錄都取完。所以最終的結果數量將是兩張表的乘積。
4、join兩張表
當我們想做兩個表的連接,而不是像上面的例子一樣得到大量的無用的結果的時候,我們就得從兩張表中選取一個join列。我下面給出的例子是使用id作為join列的。我們可以通過這種方式使得結果只映射我們需要的那一部分,從而過濾掉了無用數據。
注意:在笛卡爾乘積表中的第一行和第五行滿足了join的映射關系,從而被作為結果,其他的都被過濾掉了。
5、join多張表
上面的例子是join兩張表,如果想join多張表,我們需要在上面的結果中選擇一列,然后再在新表中選擇一列,將這兩者作為join字段,然后指定join的規則,這樣我們理論上可以join任意多張表。
首先,Table_A和Table_B做了連接,就上上面的join兩張表的例子,然后將join的結果作為一張表AB。再將AB與Table_C連接。
6、join類型
在兩張不同的表做連接有3中join類型。
1、full join
2、inner join
3、outer join(left outer join、right outer join)
在上面兩個例子中我們看到的是inner join。如果我們連接表自身就叫做self join。這個特殊類型不會混淆連接類型。
7、full join
full join和笛卡爾有些不同,笛卡爾積會獲取所有可能的結果。而full join將匹配的結果與所有左邊的表中不匹配右邊的行和右邊的表中所有不匹配左邊的行加在一起,在不匹配的地方使用NULL代替。結果行數=匹配行數+左表剩余行數+右表剩余行數。
在上面的圖片中,藍色的行是兩個表匹配的行。
第二行,左邊綠色,右邊紅色的是不匹配的,左表中的行是存在的,而右表中的字段則被null填充。
第三行,左邊紅色,右邊綠色的同樣是不匹配的,右表中的行是存在的,而左表中的字段則被null填充。
8、left join
左連接(left join)保證左表中的所有行都有,而當不匹配的時候以NULL填充右表字段。藍色匹配,紅色和綠色不匹配
9、right join
反過來,右連接(right join)保證右表中所有的行都有,而當不匹配的時候以NULL填充左表字段。

藍色匹配,紅色和綠色不匹配
10、inner join
inner join就是只列出匹配的行。
11、self join
表連接自身叫做self join。為了解釋一下這個讓我們看如下圖中的employee表。EmployeeID是此表的主鍵,ReportsTo引用了此表的主鍵。我們可以想象成這樣,ReportTo字段引用代表該雇員的上司,其上司同樣也是雇員。
看如下例子
這里,有ReportTo指向的行是Manager,所以employee是左表,Manager是右表。
12、執行順序
當連接中有where語句的時候我們需要注意連接和where的執行順序問題。
1、將where語句先于join執行,因為執行完where查詢的結果將會比較少,從而join操作性能會提升。
2、將where語句后與join執行。
以上兩者將在inner join的時候返回同樣的結果,但是當使用outer join的時候至少有一種連接操作的返回結果不同。看下面例子。
所以記住當外連接的時候盡量先執行join操作然后執行where語句。
13、連接的順序
當你想將inner join和outer join同時使用的時候join的順序也是非常重要的。
什么是連接的順序?如果我像這樣連接三張表【X inner Y】left Z,順序就是先inner join再left join。
讓我們回到上面的例子中,你想得到的結果是獲取所有客戶的名字,不管他們是否有訂單。如果他們確實有一些訂單,還要列出了客戶訂購的數量。
看如下的查詢【先outer join再inner join】
1、在Orders和Customers中進行了right join。右連接能保證你獲取所有Customer的信息,不管他是否有order。
2、現在上面的結果將和Order Details連接。但是我們需要注意的是,在右連接的結果中有兩行roderid為null的,因為這兩個customer并沒有任何order,而在后面做inner join的時候,由于orderid為null,inner join將跳過這兩行,從而導致這兩個customer的信息被過濾掉了。
再讓我們看看下面的這個查詢【先inner join再outer join】
讓我們分析一下為什么這才是我們想要的結果。
首先Order和Order Details表做inner join,所有匹配的結果都將被列出來,然后將此結果作為左表,Customer表作為右表,右表的所有行都將被列出來,不管其匹配與否(言外之意,那兩個沒有order的customer也將被列出來)。
所以,在我們同時使用inner join和outer join的時候一定要對連接的順序做慎重考慮。
14、獲取同樣數據的其他辦法
看如下查詢1、首先查詢出Customers將其作為左表
2、然后將Orders表查詢出來,仍然作為左表
3、然后查詢出Order Details表將其作為右表與Orders表進行inner join。
4、最后Customers表將于第三步查詢出的結果進行左連接。別忘了左連接將保證Customers表不丟失任何記錄。