前言
本文還是秉持之前一貫的寫作風(fēng)格,以簡單易懂的示例幫助大家了解各種join的區(qū)別。
為什么需要join
為什么需要join?join中文意思為連接,連接意味著關(guān)聯(lián)即將一個(gè)表和多個(gè)表之間關(guān)聯(lián)起來。在處理數(shù)據(jù)庫表的時(shí)候,我們經(jīng)常會(huì)發(fā)現(xiàn),需要從多個(gè)表中獲取信息,將多個(gè)表的多個(gè)字段數(shù)據(jù)組裝起來再返回給調(diào)用者。所以join的前提是這些表之間必須有關(guān)聯(lián)字段。
join的分類
join分為兩種,inner join和outer join,其中outer join分為三種,left outer join, right outer join, full outer join,另外left outer join又簡稱為left join即大家所熟知的左連接。
各種join的區(qū)別
在介紹各種join的區(qū)別之前,我們先來看一個(gè)簡單的示例:
場景描述:
互聯(lián)網(wǎng)時(shí)代,大家都喜歡在網(wǎng)上購物,尤其是淘寶和京東,所以我們選擇的場景也是大家熟悉的網(wǎng)上購物。這是一個(gè)關(guān)于一個(gè)人和他在商城買了什么商品的一個(gè)故事;
針對上述需求,我們建立了兩張表,tb_person和tb_order,其中tb_person是關(guān)于這個(gè)人的描述,tb_order是關(guān)于他購買的商品的一個(gè)描述。
我們的表結(jié)構(gòu)很簡單,tb_person只需要知道這個(gè)人是誰就可以了,所以只有三個(gè)字段id,firstname(名)和lastname(姓),同樣tb_order也很簡單,我們只要知道誰買了什么商品,所以只需要3個(gè)字段,分別是oid, oname(商品名稱), pid(購買者編號)。
tb_person:
+-----------+-------------+------+-----+---------+----------------+ |?Field?????|?Type????????|?Null?|?Key?|?Default?|?Extra??????????| +-----------+-------------+------+-----+---------+----------------+ |?pid???????|?int(11)?????|?NO???|?PRI?|?NULL????|?auto_in c rement?| |?firstname?|?var c har(50)?|?YES??|?????|?NULL????|????????????????| |?lastname??|?var c har(50)?|?YES??|?????|?NULL????|????????????????| +-----------+-------------+------+-----+---------+----------------+
tb_order:
+-------+-------------+------+-----+---------+----------------+ |?Field?|?Type????????|?Null?|?Key?|?Default?|?Extra??????????| +-------+-------------+------+-----+---------+----------------+ |?oid???|?int(11)?????|?NO???|?PRI?|?NULL????|?auto_in c rement?| |?oname?|?var c har(50)?|?YES??|?????|?NULL????|????????????????| |?pid???|?int(11)?????|?YES??|?????|?NULL????|????????????????| +-------+-------------+------+-----+---------+----------------+
接下來,我們向上述兩張表中寫入一些示例數(shù)據(jù):
data in tb_person:
+-----+-----------+----------+ |?pid?|?firstname?|?lastname?| +-----+-----------+----------+ |???1?|?andy??????|? c hen?????| |???2?|?irri??????|?wan??????| |???3?|?abby??????|?sun??????| +-----+-----------+----------+
tb_person表中有三位人員,分別是andy Chen, irri Wan, abby Sun;
data in tb_order:
+-----+----------+------+ |?oid?|?oname????|?pid??| +-----+----------+------+ |???1?|?book?????|????1?| |???2?|?phone????|????1?| |???3?|? c omputer?|????4?| +-----+----------+------+
tb_order表中記錄了3條數(shù)據(jù),人員編號為1也就是andy Chen買了兩件商品分別是book和phone,另外還有一個(gè)人員編號為4的人買了一件商品 c omputer。關(guān)于這個(gè)大家可能會(huì)產(chǎn)生疑問,為什么tb_person表中沒有人員編號為4的人呢?這里我們姑且認(rèn)為由于注冊用戶較多,我們采用了用戶分表策略,所以人員編號為4的用戶可能在另外一張人員表中。
從之前的描述我們知道,表與表之間如果要join則必須要有關(guān)聯(lián)的字段,上述示例我們看到這個(gè)關(guān)聯(lián)的字段就是pid。
根據(jù)tb_person和tb_order兩張表,我們可以看到有三種情形:
-
person表中的人購買了商品,也就是order表中有關(guān)于該用戶的商品購買記錄,我們可以從該表中查詢到該用戶買了哪些商品,如andy Chen購買了book和phone兩種商品,即pid在tb_person和tb_order兩種表中都存在;
-
person表中的人未購買商品,如irri Wan和abby Sun兩位用戶并未購買任何商品,即pid只存在于tb_person表;
-
order表中購買商品的用戶在person表中找不到記錄,如pid為4的用戶購買了一臺computer但在tb_person表中沒有該用戶的記錄,即pid只存在于tb_order表;
理解上述三種情形對于我們理解join有非常大的幫助,接下來我們將具體的分析每種join的區(qū)別:
INNER JOIN
所謂inner join的意思就是我們前面提到的情形1,pid必須在tb_person和tb_order兩張表中同時(shí)存在;
MariaDB?[demo]>?SELECT?p.pid,?p.firstname,?o.oname ????->?FROM?tb_person?p ????->?INNER?JOIN?tb_order?o ????->?ON?p.pid=o.pid;
+-----+-----------+-------+ |?pid?|?firstname?|?oname?| +-----+-----------+-------+ |???1?|?andy??????|?book??| |???1?|?andy??????|?phone?| +-----+-----------+-------+
LEFT JOIN
tb_person LEFT JOIN tb_order的意思是上述情形1,情形2的并集。LEFT JOIN的結(jié)果集不僅包含INNER JOIN的結(jié)果,而且還包含所有tb_person中沒有購買任何商品的用戶集。
MariaDB?[demo]>?SELECT?p.pid,?p.firstname,?o.oname ????->?FROM?tb_person?p ????->?LEFT?JOIN?tb_order?o ????->?ON?p.pid=o.pid;
+-----+-----------+-------+ |?pid?|?firstname?|?oname?| +-----+-----------+-------+ |???1?|?andy??????|?book??| |???1?|?andy??????|?phone?| |???2?|?irri??????|?NULL??| |???3?|?abby??????|?NULL??| +-----+-----------+-------+
RIGHT JOIN
tb_person RIGHT JOIN tb_order的意思是上述情形1和情形3的并集。RIGHT JOIN的結(jié)果集不僅包含INNER JOIN的結(jié)果,而且還包含所有tb_order中所有已經(jīng)購買商品的用戶但該用戶記錄不存在于tb_person表。
MariaDB?[demo]>?SELECT?p.pid,?p.firstname,?o.oname ????->?FROM?tb_person?p ????->?RIGHT?JOIN?tb_order?o ????->?ON?p.pid=o.pid;
+------+-----------+----------+ |?pid??|?firstname?|?oname????| +------+-----------+----------+ |????1?|?andy??????|?book?????| |????1?|?andy??????|?phone????| |?NULL?|?NULL??????|?computer?| +------+-----------+----------+
FULL JOIN
故名思議,F(xiàn)ULL JOIN就是上述情形1,2,3的并集了,但是my sql 數(shù)據(jù)庫不支持full join查詢,所以我們只能LEFT JOIN union RIGHT JOIN,才能得到FULL JOIN的結(jié)果。
MariaDB?[demo]>?SELECT?p.pid,?p.firstname,?o.oname ????->?FROM?tb_person?p ????->?LEFT?JOIN?tb_order?o ????->?ON?p.pid=o.pid ????->?UNION ????->?SELECT?p.pid,?p.firstname,?o.oname ????->?FROM?tb_person?p ????->?RIGHT?JOIN?tb_order?o ????->?ON?p.pid=o.pid;
+------+-----------+----------+ |?pid??|?firstname?|?oname????| +------+-----------+----------+ |????1?|?andy??????|?book?????| |????1?|?andy??????|?phone????| |????2?|?irri??????|?NULL?????| |????3?|?abby??????|?NULL?????| |?NULL?|?NULL??????|?computer?| +------+-----------+----------+
注:我們上述的sql語句全部基于mysql數(shù)據(jù)庫執(zhí)行。
總結(jié)
本文主要描述了 sql ?join的分類以及各種join的區(qū)別,通過簡單的示例,讓大家更清晰的去了解他們。至于什么時(shí)候使用join要視具體的情況而定,根據(jù)不同的需求采用不同的策略。
非常感謝大家的熱心回復(fù),可能有些問題的探討超出了本文的范疇,但是非常樂意大家提出問題,然后大家一起去探索去發(fā)現(xiàn)。
引用
NULL
附件
demo.sql文件
c reate?database?demo; use?demo; c reate?table?tb_person?( ????pid?int(11)?auto_in c rement, ????firstname?var c har(50), ????lastname?var c har(50), ????primary?key(pid) ); c reate?table?tb_order?( ????oid?int(11)?auto_in c rement, ????oname?var c har(50), ????pid?int(11), ????primary?key(oid) ); insert?into?tb_person(firstname,?lastname)?values('andy',' c hen'); insert?into?tb_person(firstname,?lastname)?values('irri','wan'); insert?into?tb_person(firstname,?lastname)?values('abby','sun'); insert?into?tb_order(oname,?pid)?values('book',?1); insert?into?tb_order(oname,?pid)?values('phone',?1); insert?into?tb_order(oname,?pid)?values('computer',?4);
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
