日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

你当真了解left join???【避坑指南】

發(fā)布時間:2024/2/28 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 你当真了解left join???【避坑指南】 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

現(xiàn)象

left join在我們使用mysql查詢的過程中可謂非常常見,比如博客里一篇文章有多少條評論、商城里一個貨物有多少評論、一條評論有多少個贊等等。但是由于對join、on、where等關鍵字的不熟悉,有時候會導致查詢結(jié)果與預期不符,所以今天我就來總結(jié)一下,一起避坑。

這里我先給出一個場景,并拋出兩個問題,如果你都能答對那這篇文章就不用看了。

假設有一個班級管理應用,有一個表classes,存了所有的班級;有一個表students,存了所有的學生,具體數(shù)據(jù)如下(感謝廖雪峰的在線SQL):

SELECT * FROM classes;

SELECT * FROM students;

那么現(xiàn)在有兩個需求:

  • 找出每個班級的名稱及其對應的女同學數(shù)量

  • 找出一班的同學總數(shù)

對于需求1,大多數(shù)人不假思索就能想出如下兩種sql寫法,請問哪種是對的?

SELECT?c.name,?count(s.name)?as?num?FROM?classes c?left?join?students son?s.class_id = c.idand?s.gender =?'F'group?by?c.name

或者

SELECT?c.name,?count(s.name)?as?num?FROM?classes c?left?join?students son?s.class_id = c.idwhere?s.gender =?'F'group?by?c.name

對于需求2,大多數(shù)人也可以不假思索的想出如下兩種sql寫法,請問哪種是對的?

SELECT?c.name,?count(s.name)?as?num?FROM?classes c?left?join?students son?s.class_id = c.idwhere?c.name =?'一班'?group?by?c.name

或者

SELECT?c.name,?count(s.name)?as?num?FROM?classes c?left?join?students son?s.class_id = c.idand?c.name =?'一班'?group?by?c.name

請不要繼續(xù)往下翻 !!先給出你自己的答案,正確答案就在下面。

答案是兩個需求都是第一條語句是正確的,要搞清楚這個問題,就得明白mysql對于left join的執(zhí)行原理,下節(jié)進行展開。

根源

mysql 對于left join的采用類似嵌套循環(huán)的方式來進行從處理,以下面的語句為例:

SELECT?*?FROM?LT?LEFT?JOIN?RT?ON?P1(LT,RT))?WHERE?P2(LT,RT)

其中P1是on過濾條件,缺失則認為是TRUE,P2是where過濾條件,缺失也認為是TRUE,該語句的執(zhí)行邏輯可以描述為:

FOR?each row lt in LT {// 遍歷左表的每一行BOOL b =?FALSE;FOR?each row rt in RT such that P1(lt, rt) {// 遍歷右表每一行,找到滿足join條件的行IF?P2(lt, rt) {//滿足 where 過濾條件t:=lt||rt;//合并行,輸出該行}b=TRUE;// lt在RT中有對應的行}IF?(!b) {?// 遍歷完RT,發(fā)現(xiàn)lt在RT中沒有有對應的行,則嘗試用null補一行IF?P2(lt,NULL) {// 補上null后滿足 where 過濾條件t:=lt||NULL;?// 輸出lt和null補上的行}} }

當然,實際情況中MySQL會使用buffer的方式進行優(yōu)化,減少行比較次數(shù),不過這不影響關鍵的執(zhí)行流程,不在本文討論范圍之內(nèi)。

從這個偽代碼中,我們可以看出兩點:

如果想對右表進行限制,則一定要在on條件中進行,若在where中進行則可能導致數(shù)據(jù)缺失,導致左表在右表中無匹配行的行在最終結(jié)果中不出現(xiàn),違背了我們對left join的理解。因為對左表無右表匹配行的行而言,遍歷右表后b=FALSE,所以會嘗試用NULL補齊右表,但是此時我們的P2對右表行進行了限制,NULL若不滿足P2(NULL一般都不會滿足限制條件,除非IS NULL這種),則不會加入最終的結(jié)果中,導致結(jié)果缺失。

?

如果沒有where條件,無論on條件對左表進行怎樣的限制,左表的每一行都至少會有一行的合成結(jié)果,對左表行而言,若右表若沒有對應的行,則右表遍歷結(jié)束后b=FALSE,會用一行NULL來生成數(shù)據(jù),而這個數(shù)據(jù)是多余的。所以對左表進行過濾必須用where。

下面展開兩個需求的錯誤語句的執(zhí)行結(jié)果和錯誤原因:

需求1

需求2

需求1由于在where條件中對右表限制,導致數(shù)據(jù)缺失(四班應該有個為0的結(jié)果)

需求2由于在on條件中對左表限制,導致數(shù)據(jù)多余(其他班的結(jié)果也出來了,還是錯的)

總結(jié)

通過上面的問題現(xiàn)象和分析,可以得出了結(jié)論:在left join語句中,左表過濾必須放where條件中,右表過濾必須放on條件中,這樣結(jié)果才能不多不少,剛剛好。

SQL 看似簡單,其實也有很多細節(jié)原理在里面,一個小小的混淆就會造成結(jié)果與預期不符,所以平時要注意這些細節(jié)原理,避免關鍵時候出錯。

摘自:?segmentfault.com/a/1190000020458807

總結(jié)

以上是生活随笔為你收集整理的你当真了解left join???【避坑指南】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。