mysql中的left join、right join、join(inner join),外連接區別

以下圖片數據來源:https://segmentfault.com/a/1190000017067294

下面開始說mysql中的left join、right join、join(inner join),外連接的區別

sql準備:name表和classes表

INSERT INTO name(name, age, grade) VALUES ('小白', 20, 1), ('小黑', 21, 2), ('小紅', 22, 3), ('小花', 23, 4), ('小綠', 24, 5) ;
INSERT INTO classes (cname) VALUES ('歐陽鋒'), ('楊過'), ('喬峯');
INSERT INTO classes (id,cname) VALUES (7, '溜噠');

table_name

table_classes.png


各種join的使用

1、left join 即爲以sql語句中的左邊的表爲主要表關聯右邊的表,其中使用on作爲條件篩選,where爲過濾條件

以name爲主表,classes爲關聯表

SELECT * FROM   name t1   LEFT JOIN   classes t2   ON   t1.grade = t2.id;

name_left_join_classes.png

left_join.png

可以看到小花和小綠並沒有關聯到classes中的任何數據,我們以name爲左表,然後以classes爲右表然後進行關聯,展示5行數據,條件不符合的小花和小綠(沒有想對應的班級、師傅領養),即爲野生,需要使用null補全,而溜噠同學乾脆直接無視。

2、right join :以classes爲主表以name爲關聯表

SELECT * FROM   name t1   RIGHT JOIN   classes t2   ON   t1.grade = t2.id;

name_right_join_classes.png

right_join.png

可以看到以classes爲主表,以name爲關聯表結果爲4條,雖然溜噠同學什麼也不會,但是還是可以下班之後溜噠溜噠溜溜狗的嘛(單身狗也是狗)!!

3、無主次關聯join(inner join)

SELECT *
FROM name t1 JOIN classes t2 ON t1.grade = t2.id;

name_join_classes

join(inner join).png
而join可以看到只有兩個表完全的交集才能被顯示出來,這裏顯示3條。

4、外連接,只能用union

傳說中的full join(mysql不支持,使用union來進行模擬)

SELECT *
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id
UNION
SELECT *
FROM name t1 RIGHT JOIN classes t2 ON t1.grade = t2.id;

union_left_right.png

 

可以看到,outer join表示全並集,即6條數據。

綜上所述,可以整理得到:以哪個表爲主表則檢索出哪個表的全部內容,關聯表中符合on關聯要求的可以進行數據關聯,如果不符合要求,那麼需要以null行展示;如果使用join進行關聯那麼無主次關聯,只顯示符合要求的數據。


on、where的使用

on:兩個表關聯的時候使用,決定被關聯的表的數據是否能與主表關聯(name left join classes on name.grade = classes.id)主表name數據完全顯示,不被關聯的數據需要在grade側以null數據補全
where:兩個表關聯後,再進行條件過濾
區別:on主要作用再被關聯表中,where作用在關聯後的左右數據上

基本作用

SELECT *
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id
WHERE t2.id IN (1, 3);

left_join_on_where.png
然後,把where中的條件拿到on中

SELECT *
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id AND t2.id IN(1,3);

left_join_on_no_where.png

可以看到,加上where條件後作用再left join on關聯後的數據,將不符合where條件的全部去掉,只使用on,和我們先前得到的結論一致,不符合關聯條件的需要null行補充。

on where 約束力相同的時候

先回顧一下join(inner join)。

SELECT *
FROM name t1 JOIN classes t2 ON t1.grade = t2.id AND t2.id IN(1,3);

join(inner join).png
得到join條件的兩條數據。如果我們把追加的t2.id in(1,3)拿到where中是什麼情況呢?

SELECT *
FROM name t1 JOIN classes t2 ON t1.grade = t2.id
WHERE t2.id IN(1,3);

join_where.png
可以看到,此處的t2.id IN(1,3)在on和在where中效果一樣。溜噠同學表示可以理解爲是join關鍵詞造成的,應爲join表示完全符合條件的才進行關聯展示,不會進行數據null行補充,而where用於過濾數據,那麼也是表示符合條件的進行展示。(如果問我爲啥不把 t1.grade = t2.id也拿到where中去,那麼同學可以自己動手試試嘛!)

各種join、on、where該怎麼聯合使用

首先拿出最開始的例子,普通left join和on使用,展示5條數據。

SELECT *
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id

left_join_on.png
然後我們進行數據統計,使用count()來進行查看數據條數。

SELECT count(t1.id)
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id;```

![count(name.id).png](http://upload-images.jianshu.io/upload_images/3935727-d3d73cdfd053008b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

SELECT count(t2.id)
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id;


![count(classes.id).png](http://upload-images.jianshu.io/upload_images/3935727-9ffa8ca198c539a8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
這裏可以看到count(null)是不計入數據統計的(不要問爲什麼),那麼可以看出,關聯後的統計在各自部分統計是沒有什麼問題的,name表側是5條,而符合on條件的classes側是3條。由此,可以引申出另一個容易出錯的地方:在on中如果有多個條件進行關聯限制,此時如果這些條件中有想進行過濾的那麼需要拿到where中去,纔會進行正確數據篩選。
####多on條件搭配where使用(不要用錯)

SELECT *
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id AND t2.id IN(1, 3);`
left_join_on_no_where.png

count(t1.id) = 5 
count(t2.id) = 2
這裏如果想要統計符合classes.id in(1,3)的數據的時候,一定要把t2.id in(1,3)拿到where中去。比如,希望統計西毒、喬峯這兩個前輩的高徒的年齡和需要將t2.id in(1,3)放到where中去。

SELECT sum(t1.age)
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id AND t2.id IN(1, 3);

error_count(age).png

SELECT sum(t1.age)
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id 
WHERE t2.id IN(1, 3);

right_count(age).png
那麼有沒有可能不用where數據也能統計對的情況呢?
必然有(就好像數學老師說,這道題選A對不對啊??大多數情況下不對。。。),兩個表進行關聯,不使用where,但是當兩部分有計算操作的時候,效果是理想的。
我們操作name中的age去加上classes中的id,(就當做師傅給徒弟傳各自id數值的年限的內力)

SELECT t1.age+t2.id
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id AND t2.id IN(1, 3);

name.age+classes.id_on.png

SELECT t1.age+t2.id
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id
WHERE t2.id IN(1, 3);

name.age+classes.id_where.png
如上,兩部分進行了加和計算操作,這時候如果再進行sum()等統計操作,其實出來的數據是一樣的。使用規範,看你所在團隊更傾向於哪一種。當然,如果這裏使用join 內連接,那麼就沒有這麼多不同了。


關於性能

首先必須明確的事情就是:

  1. 使用關聯肯定是要從關聯表中拿數據進行展示。
  2. 數據庫輸出的數據越多,性能越低。
  3. 數據庫有自己的優化引擎,可能會將你的sql語句進行自我優化。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章