mysql中的left join、right join、join

sql準(zhǔn)備

INSERT INTO name(name, age, grade) VALUES ('小白', 20, 1), ('小黑', 21, 2), ('小紅', 22, 3), ('小花', 23, 4), ('小綠', 24, 5) ;
INSERT INTO classes (cname) VALUES ('歐陽(yáng)鋒'), ('楊過(guò)'), ('喬峰');
INSERT INTO classes (id,cname) VALUES (7, '溜噠');
table_name
table_classes.png

各種join的使用

left join 即為以sql語(yǔ)句中的左邊的表為主要表關(guān)聯(lián)右邊的表,其中使用on作為條件篩選,where為過(guò)濾條件

以name為主表,classes為關(guān)聯(lián)表
SELECT *
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id;```

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

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

可以看到小花和小綠并沒(méi)有關(guān)聯(lián)到classes中的任何數(shù)據(jù),我們以name為左表,然后以classes為右表然后進(jìn)行關(guān)聯(lián),展示5行數(shù)據(jù),條件不符合的小花和小綠(沒(méi)有想對(duì)應(yīng)的班級(jí)、師傅領(lǐng)養(yǎng)),即為野生,需要使用null補(bǔ)全,而溜噠同學(xué)干脆直接無(wú)視。
#####以classes為主表以name為關(guān)聯(lián)表
```sql
SELECT *
FROM name t1 RIGHT JOIN classes t2 ON t1.grade = t2.id;```


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


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


可以看到以classes為主表,以name為關(guān)聯(lián)表結(jié)果為4條,雖然溜噠同學(xué)什么也不會(huì),但是還是可以下班之后溜噠溜噠溜溜狗的嘛(單身狗也是狗)??!
####無(wú)主次關(guān)聯(lián)join(inner join)
```sql
SELECT *
FROM name t1 JOIN classes t2 ON t1.grade = t2.id;```


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



![join(inner join).png](http://upload-images.jianshu.io/upload_images/3935727-0a915919061d8a54.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
而join可以看到只有兩個(gè)表完全的交集才能被顯示出來(lái),這里顯示3條。果然,最后登上光明頂?shù)倪€是名師下邊的高徒。我等可以繼續(xù)溜噠溜噠。

####傳說(shuō)中的full join(mysql不支持,使用union來(lái)進(jìn)行模擬)
```sql
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](http://upload-images.jianshu.io/upload_images/3935727-4393a8ae2701705e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


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

可以看到,full join表示全并集,即6條數(shù)據(jù)。論起溜噠溜噠溜溜單身汪,溜噠同學(xué)還是可以的。



綜上所述,可以整理得到:以哪個(gè)表為主表則檢索出哪個(gè)表的全部?jī)?nèi)容,關(guān)聯(lián)表中符合on關(guān)聯(lián)要求的可以進(jìn)行數(shù)據(jù)關(guān)聯(lián),如果不符合要求,那么需要以null行展示;如果使用join進(jìn)行關(guān)聯(lián)那么無(wú)主次關(guān)聯(lián),只顯示符合要求的數(shù)據(jù)。
***
#on、where的使用
on:兩個(gè)表關(guān)聯(lián)的時(shí)候使用,決定被關(guān)聯(lián)的表的數(shù)據(jù)是否能與主表關(guān)聯(lián)(name left join classes on name.grade = classes.id)主表name數(shù)據(jù)完全顯示,不被關(guān)聯(lián)的數(shù)據(jù)需要在grade側(cè)以null數(shù)據(jù)補(bǔ)全
where:兩個(gè)表關(guān)聯(lián)后,再進(jìn)行條件過(guò)濾
區(qū)別:on主要作用再被關(guān)聯(lián)表中,where作用在關(guān)聯(lián)后的左右數(shù)據(jù)上
####基本作用
```sql
SELECT *
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id
WHERE t2.id IN (1, 3);```

![left_join_on_where.png](http://upload-images.jianshu.io/upload_images/3935727-aa902f2c80f9b5c8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
然后,把where中的條件拿到on中
```sql
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](http://upload-images.jianshu.io/upload_images/3935727-117623b6cc6dd2e5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

可以看到,加上where條件后作用再left join  on關(guān)聯(lián)后的數(shù)據(jù),將不符合where條件的全部去掉,只使用on,和我們先前得到的結(jié)論一致,不符合關(guān)聯(lián)條件的需要null行補(bǔ)充。
####on where 約束力相同的時(shí)候
先回顧一下join(inner join)。

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

![join(inner join).png](http://upload-images.jianshu.io/upload_images/3935727-58751c62ecc35e12.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
得到j(luò)oin條件的兩條數(shù)據(jù)。如果我們把追加的t2.id in(1,3)拿到where中是什么情況呢?

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

![join_where.png](http://upload-images.jianshu.io/upload_images/3935727-58751c62ecc35e12.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
可以看到,此處的t2.id IN(1,3)在on和在where中效果一樣。溜噠同學(xué)表示可以理解為是join關(guān)鍵詞造成的,應(yīng)為join表示完全符合條件的才進(jìn)行關(guān)聯(lián)展示,不會(huì)進(jìn)行數(shù)據(jù)null行補(bǔ)充,而where用于過(guò)濾數(shù)據(jù),那么也是表示符合條件的進(jìn)行展示。(如果問(wèn)我為啥不把 t1.grade = t2.id也拿到where中去,那么同學(xué)可以自己動(dòng)手試試嘛!)
####各種join、on、where該怎么聯(lián)合使用
首先拿出最開始的例子,普通left join和on使用,展示5條數(shù)據(jù)。
```sql
SELECT *
FROM name t1 LEFT JOIN classes t2 ON t1.grade = t2.id```

![left_join_on.png](http://upload-images.jianshu.io/upload_images/3935727-528eb3a49913b0a0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
然后我們進(jìn)行數(shù)據(jù)統(tǒng)計(jì),使用count()來(lái)進(jìn)行查看數(shù)據(jù)條數(shù)。
```sql
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)
```sql
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)是不計(jì)入數(shù)據(jù)統(tǒng)計(jì)的(不要問(wèn)為什么),那么可以看出,關(guān)聯(lián)后的統(tǒng)計(jì)在各自部分統(tǒng)計(jì)是沒(méi)有什么問(wèn)題的,name表側(cè)是5條,而符合on條件的classes側(cè)是3條。由此,可以引申出另一個(gè)容易出錯(cuò)的地方:在on中如果有多個(gè)條件進(jìn)行關(guān)聯(lián)限制,此時(shí)如果這些條件中有想進(jìn)行過(guò)濾的那么需要拿到where中去,才會(huì)進(jìn)行正確數(shù)據(jù)篩選。
####多on條件搭配where使用(不要用錯(cuò))
```sql
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](http://upload-images.jianshu.io/upload_images/3935727-117623b6cc6dd2e5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

count(t1.id) = 5 
count(t2.id) = 2
這里如果想要統(tǒng)計(jì)符合classes.id in(1,3)的數(shù)據(jù)的時(shí)候,一定要把t2.id in(1,3)拿到where中去。比如,希望統(tǒng)計(jì)西毒、喬峰這兩個(gè)前輩的高徒的年齡和需要將t2.id in(1,3)放到where中去。
```sql
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](http://upload-images.jianshu.io/upload_images/3935727-124b9e436f939a0e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

```sql
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](http://upload-images.jianshu.io/upload_images/3935727-3d43583862fdc403.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
那么有沒(méi)有可能不用where數(shù)據(jù)也能統(tǒng)計(jì)對(duì)的情況呢?
必然有(就好像數(shù)學(xué)老師說(shuō),這道題選A對(duì)不對(duì)啊??大多數(shù)情況下不對(duì)。。。),兩個(gè)表進(jìn)行關(guān)聯(lián),不使用where,但是當(dāng)兩部分有計(jì)算操作的時(shí)候,效果是理想的。
我們操作name中的age去加上classes中的id,(就當(dāng)做師傅給徒弟傳各自id數(shù)值的年限的內(nèi)力)
```sql
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](http://upload-images.jianshu.io/upload_images/3935727-279b6410b0dbf59f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

```sql
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](http://upload-images.jianshu.io/upload_images/3935727-d69ad90f7c96c2cc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
如上,兩部分進(jìn)行了加和計(jì)算操作,這時(shí)候如果再進(jìn)行sum()等統(tǒng)計(jì)操作,其實(shí)出來(lái)的數(shù)據(jù)是一樣的。使用規(guī)范,看你所在團(tuán)隊(duì)更傾向于哪一種。當(dāng)然,如果這里使用join 內(nèi)連接,那么就沒(méi)有這么多不同了。
***
####關(guān)于性能
首先必須明確的事情就是:
1. 使用關(guān)聯(lián)肯定是要從關(guān)聯(lián)表中拿數(shù)據(jù)進(jìn)行展示。
2. 數(shù)據(jù)庫(kù)輸出的數(shù)據(jù)越多,性能越低。
3. 數(shù)據(jù)庫(kù)有自己的優(yōu)化引擎,可能會(huì)將你的sql語(yǔ)句進(jìn)行自我優(yōu)化。
***
溜噠同學(xué)本身技術(shù)不好,這次不進(jìn)行性能討論,從輸出上來(lái)看join性能要好一些,但是在工作中會(huì)存在明顯的left join比join快的情況,網(wǎng)上都是說(shuō)select中的統(tǒng)計(jì)并沒(méi)有用到關(guān)聯(lián)表的數(shù)據(jù),所以存在數(shù)據(jù)庫(kù)優(yōu)化將關(guān)聯(lián)表不進(jìn)行關(guān)聯(lián),然后直接進(jìn)行統(tǒng)計(jì)的情況,此時(shí),join還是需要進(jìn)行關(guān)聯(lián)(雙向的), 所以會(huì)出現(xiàn)left join 比join快的情況。同時(shí)也會(huì)出現(xiàn)索引使用的問(wèn)題。
當(dāng)然這只是網(wǎng)上的文章,不是自己操作的沒(méi)有辦法說(shuō)服自己,還是多看看書,做點(diǎn)小實(shí)驗(yàn)明確一下。這是溜噠同學(xué)第一篇博客,請(qǐng)大家輕拍?。。〞?huì)有人看么?衰.jpg)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容