朋的博客

          MySQL資料,Java技術(shù),管理思想,博弈論,Ajax,XP極限編程,H.264,HEVC,HDR
          隨筆 - 86, 文章 - 59, 評(píng)論 - 1069, 引用 - 0
          數(shù)據(jù)加載中……

          MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)

          MySQL的聯(lián)結(jié)(Join)語(yǔ)法

          1.內(nèi)聯(lián)結(jié)、外聯(lián)結(jié)、左聯(lián)結(jié)、右聯(lián)結(jié)的含義及區(qū)別:

          ?

          在講MySQLJoin語(yǔ)法前還是先回顧一下聯(lián)結(jié)的語(yǔ)法,呵呵,其實(shí)連我自己都忘得差不多了,那就大家一起溫習(xí)吧(如果內(nèi)容有錯(cuò)誤或有疑問(wèn),可以來(lái)信咨詢:陳朋奕 chenpengyi#gmail.com),國(guó)內(nèi)關(guān)于MySQL聯(lián)結(jié)查詢的資料十分少,相信大家在看了本文后會(huì)對(duì)MySQL聯(lián)結(jié)語(yǔ)法有相當(dāng)清晰的了解,也不會(huì)被Oracle的外聯(lián)結(jié)的(“+”號(hào))弄得糊涂了。

          ?

          SQL標(biāo)準(zhǔn)中規(guī)劃的(Join)聯(lián)結(jié)大致分為下面四種:

          1.? 內(nèi)聯(lián)結(jié):將兩個(gè)表中存在聯(lián)結(jié)關(guān)系的字段符合聯(lián)結(jié)關(guān)系的那些記錄形成記錄集的聯(lián)結(jié)。

          2.? 外聯(lián)結(jié):分為外左聯(lián)結(jié)和外右聯(lián)結(jié)。

          左聯(lián)結(jié)AB表的意思就是將表A中的全部記錄和表B中聯(lián)結(jié)的字段與表A的聯(lián)結(jié)字段符合聯(lián)結(jié)條件的那些記錄形成的記錄集的聯(lián)結(jié),這里注意的是最后出來(lái)的記錄集會(huì)包括表A的全部記錄。

          右聯(lián)結(jié)AB表的結(jié)果和左聯(lián)結(jié)BA的結(jié)果是一樣的,也就是說(shuō):

          Select A.name B.name From A Left Join B On A.id=B.id

          Select A.name B.name From B Right Join A on B.id=A.id執(zhí)行后的結(jié)果是一樣的。

          3.全聯(lián)結(jié):將兩個(gè)表中存在聯(lián)結(jié)關(guān)系的字段的所有記錄取出形成記錄集的聯(lián)結(jié)(這個(gè)不需要記憶,只要是查詢中提到了的表的字段都會(huì)取出,無(wú)論是否符合聯(lián)結(jié)條件,因此意義不大)。

          4.無(wú)聯(lián)結(jié):不用解釋了吧,就是沒(méi)有使用聯(lián)結(jié)功能唄,也有自聯(lián)結(jié)的說(shuō)法。

          ?

          這里我有個(gè)比較簡(jiǎn)便的記憶方法,內(nèi)外聯(lián)結(jié)的區(qū)別是內(nèi)聯(lián)結(jié)將去除所有不符合條件的記錄,而外聯(lián)結(jié)則保留其中部分。外左聯(lián)結(jié)與外右聯(lián)結(jié)的區(qū)別在于如果用A左聯(lián)結(jié)BA中所有記錄都會(huì)保留在結(jié)果中,此時(shí)B中只有符合聯(lián)結(jié)條件的記錄,而右聯(lián)結(jié)相反,這樣也就不會(huì)混淆了。其實(shí)大家回憶高等教育出版社出版的《數(shù)據(jù)庫(kù)系統(tǒng)概論》書中講到關(guān)系代數(shù)那章(就是將笛卡兒積和投影那章)的內(nèi)容,相信不難理解這些聯(lián)結(jié)功能的內(nèi)涵。

          ?

          2.? MySQL聯(lián)結(jié)(Join)的語(yǔ)法

          ?

          MySQL支持Select和某些UpdateDelete情況下的Join語(yǔ)法,具體語(yǔ)法上的細(xì)節(jié)有:

          ?

          table_references:

          ??? table_reference [, table_reference] …

          ?

          table_reference:

          ??? table_factor

          ? | join_table

          ?

          table_factor:

          ??? tbl_name [[AS] alias]

          ??????? [{USE|IGNORE|FORCE} INDEX (key_list)]

          ? | ( table_references )

          ? | { OJ table_reference LEFT OUTER JOIN table_reference

          ??????? ON conditional_expr }

          ?

          join_table:

          ??? table_reference [INNER | CROSS] JOIN table_factor [join_condition]

          ? | table_reference STRAIGHT_JOIN table_factor

          ? | table_reference STRAIGHT_JOIN table_factor ON condition

          ? | table_reference LEFT [OUTER] JOIN table_reference join_condition

          ? | table_reference NATURAL [LEFT [OUTER]] JOIN table_factor

          ? | table_reference RIGHT [OUTER] JOIN table_reference join_condition

          ? | table_reference NATURAL [RIGHT [OUTER]] JOIN table_factor

          ?

          join_condition:

          ??? ON conditional_expr | USING (column_list)

          ?

          上面的用法摘自權(quán)威資料,不過(guò)大家看了是否有點(diǎn)暈?zāi)兀亢呛牵瑧?yīng)該問(wèn)題主要還在于table_reference是什么,table_factor又是什么?這里的table_reference其實(shí)就是表的引用的意思,因?yàn)樵?/SPAN>MySQL看來(lái),聯(lián)結(jié)就是一種對(duì)表的引用,因此把需要聯(lián)結(jié)的表定義為table_reference,同時(shí)在SQL Standard中也是如此看待的。而table_factor則是MySQL對(duì)這個(gè)引用的功能上的增強(qiáng)和擴(kuò)充,使得引用的表可以是括號(hào)內(nèi)的一系列表,如下面例子中的JOIN后面括號(hào):

          ?

          SELECT * FROM t1 LEFT JOIN (t2, t3, t4) ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

          ?

          這個(gè)語(yǔ)句的執(zhí)行結(jié)果和下面語(yǔ)句其實(shí)是一樣的:

          ?

          SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)

          ???????????????? ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

          ?

          這兩個(gè)例子不僅讓我們了解了MySQLtable_factortable_reference含義,同時(shí)能理解一點(diǎn)CROSS JOIN的用法,我要補(bǔ)充的是在MySQL現(xiàn)有版本中CROSS JOIN的作用和INNER JOIN是一樣的(雖然在SQL Standard中是不一樣的,然而在MySQL中他們的區(qū)別僅僅是INNER JOIN需要附加ON參數(shù)的語(yǔ)句,而CROSS JOIN不需要)。

          既然說(shuō)到了ON語(yǔ)句,那就解釋一下吧,ON語(yǔ)句其實(shí)和WHERE語(yǔ)句功能大致相當(dāng),只是這里的ON語(yǔ)句是專門針對(duì)聯(lián)結(jié)表的,ON語(yǔ)句后面的條件的要求和書寫方式和WHERE語(yǔ)句的要求是一樣的,大家基本上可以把ON當(dāng)作WHERE用。

          大家也許也看到了OJ table_reference LEFT OUTER JOIN table_reference這個(gè)句子,這不是MySQL的標(biāo)準(zhǔn)寫法,只是為了和ODBCSQL語(yǔ)法兼容而設(shè)定的,我很少用,Java的人更是不會(huì)用,所以也不多解釋了。

          那下面就具體講講簡(jiǎn)單的JOIN的用法了。首先我們假設(shè)有2個(gè)表AB,他們的表結(jié)構(gòu)和字段分別為:

          ?

          A

          ID

          Name

          1

          Tim

          2

          Jimmy

          3

          John

          4

          Tom

          B

          ID

          Hobby

          1

          Football

          2

          Basketball

          2

          Tennis

          4

          Soccer

          ?

          1.? 內(nèi)聯(lián)結(jié):

          Select A.Name B.Hobby from A, B where A.id = B.id,這是隱式的內(nèi)聯(lián)結(jié),查詢的結(jié)果是:

          Name

          Hobby

          Tim

          Football

          Jimmy

          Basketball

          Jimmy

          Tennis

          Tom

          Soccer

          它的作用和 Select A.Name from A INNER JOIN B ON A.id = B.id是一樣的。這里的INNER JOIN換成CROSS JOIN也是可以的。

          2.? 外左聯(lián)結(jié)

          Select A.Name from A Left JOIN B ON A.id = B.id,典型的外左聯(lián)結(jié),這樣查詢得到的結(jié)果將會(huì)是保留所有A表中聯(lián)結(jié)字段的記錄,若無(wú)與其相對(duì)應(yīng)的B表中的字段記錄則留空,結(jié)果如下:

          Name

          Hobby

          Tim

          Football

          Jimmy

          BasketballTennis

          John

          ?

          Tom

          Soccer

          所以從上面結(jié)果看出,因?yàn)?/SPAN>A表中的John記錄的ID沒(méi)有在B表中有對(duì)應(yīng)ID,因此為空,但Name欄仍有John記錄。

          3.? 外右聯(lián)結(jié)

          如果把上面查詢改成外右聯(lián)結(jié):Select A.Name from A Right JOIN B ON A.id = B.id,則結(jié)果將會(huì)是:

          Name

          Hobby

          Tim

          Football

          Jimmy

          Basketball

          Jimmy

          Tennis

          Tom

          Soccer

          這樣的結(jié)果都是我們可以從外左聯(lián)結(jié)的結(jié)果中猜到的了。

          說(shuō)到這里大家是否對(duì)聯(lián)結(jié)查詢了解多了?這個(gè)原本看來(lái)高深的概念一下子就理解了,恍然大悟了吧(呵呵,開(kāi)玩笑了)?最后給大家講講MySQL聯(lián)結(jié)查詢中的某些參數(shù)的作用:

          ?

          1USING (column_list):其作用是為了方便書寫聯(lián)結(jié)的多對(duì)應(yīng)關(guān)系,大部分情況下USING語(yǔ)句可以用ON語(yǔ)句來(lái)代替,如下面例子:

          ?

          a LEFT JOIN b USING (c1,c2,c3),其作用相當(dāng)于下面語(yǔ)句

          a LEFT JOIN b ON a.c1=b.c1 AND a.c2=b.c2 AND a.c3=b.c3

          ?

          只是用ON來(lái)代替會(huì)書寫比較麻煩而已。

          ?

          2NATURAL [LEFT] JOIN:這個(gè)句子的作用相當(dāng)于INNER JOIN,或者是在USING子句中包含了聯(lián)結(jié)的表中所有字段的Left JOIN(左聯(lián)結(jié))。

          ?

          3STRAIGHT_JOIN:由于默認(rèn)情況下MySQL在進(jìn)行表的聯(lián)結(jié)的時(shí)候會(huì)先讀入左表,當(dāng)使用了這個(gè)參數(shù)后MySQL將會(huì)先讀入右表,這是個(gè)MySQL的內(nèi)置優(yōu)化參數(shù),大家應(yīng)該在特定情況下使用,譬如已經(jīng)確認(rèn)右表中的記錄數(shù)量少,在篩選后能大大提高查詢速度。

          ?

          最后要說(shuō)的就是,在MySQL5.0以后,運(yùn)算順序得到了重視,所以對(duì)多表的聯(lián)結(jié)查詢可能會(huì)錯(cuò)誤以子聯(lián)結(jié)查詢的方式進(jìn)行。譬如你需要進(jìn)行多表聯(lián)結(jié),因此你輸入了下面的聯(lián)結(jié)查詢:

          ?

          SELECT t1.id,t2.id,t3.id

          ??? FROM t1,t2

          ??? LEFT JOIN t3 ON (t3.id=t1.id)

          ??? WHERE t1.id=t2.id;

          ?

          但是MySQL并不是這樣執(zhí)行的,其后臺(tái)的真正執(zhí)行方式是下面的語(yǔ)句:

          ?

          SELECT t1.id,t2.id,t3.id

          ??? FROM t1,(? t2 LEFT JOIN t3 ON (t3.id=t1.id)? )

          ??? WHERE t1.id=t2.id;

          ?

          這并不是我們想要的效果,所以我們需要這樣輸入:

          ?

          SELECT t1.id,t2.id,t3.id

          ??? FROM (t1,t2)

          ??? LEFT JOIN t3 ON (t3.id=t1.id)

          ??? WHERE t1.id=t2.id;

          ?

          在這里括號(hào)是相當(dāng)重要的,因此以后在寫這樣的查詢的時(shí)候我們不要忘記了多寫幾個(gè)括號(hào),至少這樣能避免很多錯(cuò)誤(因?yàn)檫@樣的錯(cuò)誤是很難被開(kāi)發(fā)人員發(fā)現(xiàn)的)。如果對(duì)上面內(nèi)容有疑問(wèn)可以來(lái)信查詢:陳朋奕 chenpengyi#gmail.com,轉(zhuǎn)載請(qǐng)注明出處及作者。

          posted on 2005-10-17 22:53 benchensz 閱讀(51988) 評(píng)論(24)  編輯  收藏 所屬分類: 隨便寫寫(比較有用,值得看看)

          評(píng)論

          # re: MySQL的聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          果然清楚,謝謝樓上給這么好的講解,卻是現(xiàn)在網(wǎng)上對(duì)這個(gè)的解釋太少了,即使有也是比較無(wú)聊的。謝謝了。
          2005-10-18 12:04 | tim163

          # re: MySQL的聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          謝謝你的講解,以前是學(xué)的SQL SERVER的連接,看來(lái)MYSQL的連接也差不多,更深刻的理解了。
          2005-10-21 21:25 | mpshun

          # re: MySQL的聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          我也頂一個(gè)
          很簡(jiǎn)潔明了,喜歡這個(gè),不知道樓主現(xiàn)在是做什么工作?
          2005-10-21 22:31 | kknd

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          這個(gè)是我見(jiàn)過(guò)講解聯(lián)接最好的了。
          2005-11-01 17:33 | bill lee

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          引用:**********************************
          譬如你需要進(jìn)行多表聯(lián)結(jié),因此你輸入了下面的聯(lián)結(jié)查詢:

          SELECT t1.id,t2.id,t3.id
          FROM t1,t2
          LEFT JOIN t3 ON (t3.id=t1.id)
          WHERE t1.id=t2.id;

          但是MySQL并不是這樣執(zhí)行的,其后臺(tái)的真正執(zhí)行方式是下面的語(yǔ)句:

          SELECT t1.id,t2.id,t3.id
          FROM t1,( t2 LEFT JOIN t3 ON (t3.id=t1.id) )
          WHERE t1.id=t2.id;
          結(jié)束引用********************************

          請(qǐng)問(wèn)大蝦您是怎么知道m(xù)ysql后臺(tái)的執(zhí)行方式?能不能給點(diǎn)線索,小弟實(shí)在不明白好端端的輸入怎么就給改了方式運(yùn)行哪?謝謝
          2006-01-02 21:03 | 一葉小舟

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          3x,溫習(xí)了一下,真的很清楚
          2006-01-04 14:31 | lisa

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          解釋清晰。非常感謝。
          2006-02-11 15:36 | Foon

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          謝謝樓主,好東西
          2009-03-11 10:49 | ronald

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          謝謝分享,寫得很清楚,很容易看懂
          2009-03-30 18:30 | SiemenLiu

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)[未登錄](méi)  回復(fù)  更多評(píng)論   

          看了很多,在這里才真的明白了,謝謝
          2009-04-14 15:46 | Jun

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          受益匪淺!
          2009-04-29 10:36 | fenix

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          受益匪淺
          2010-09-25 16:32 | ai

          # 提問(wèn)  回復(fù)  更多評(píng)論   

          在“2.外左聯(lián)結(jié)”中的結(jié)果第二行Hobby有兩個(gè)值,應(yīng)該怎樣把這兩個(gè)值從結(jié)果集中取出來(lái)呢?
          2011-08-08 15:06 | ts

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          簡(jiǎn)單明了
          2011-09-25 15:00 | nx

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          寫的太好了,學(xué)習(xí)啦
          2011-11-02 17:39 | 瞬間的永恒

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          SELECT b. * , k.id AS likeid , f.id AS followid ,m.username,m.domain FROM `anran_blog` AS b LEFT JOIN `anran_likes` AS k ON ( b.bid = k.bid AND k.uid ='' ) LEFT JOIN `anran_follow` AS f ON ( b.uid = f.touid and f.uid = '' ) LEFT JOIN `anran_member` as m on b.uid = m.uid where b.open = 1
          2011-12-04 17:33 | mr.doooger

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          可以幫忙解釋這句sql語(yǔ)句嗎?謝謝
          SELECT b. * , k.id AS likeid , f.id AS followid ,m.username,m.domain FROM `anran_blog` AS b LEFT JOIN `anran_likes` AS k ON ( b.bid = k.bid AND k.uid ='' ) LEFT JOIN `anran_follow` AS f ON ( b.uid = f.touid and f.uid = '' ) LEFT JOIN `anran_member` as m on b.uid = m.uid where b.open = 1
          2011-12-04 17:34 | mr.doooger

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          多謝,講的不錯(cuò)
          2012-08-20 15:49 | juffun

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)[未登錄](méi)  回復(fù)  更多評(píng)論   

          大概懂了些..謝謝了
          2012-11-29 21:01 | cone

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          謝謝大哥,大哥辛苦了!
          2013-09-08 20:13 | Ice_Xue

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)  回復(fù)  更多評(píng)論   

          很激動(dòng)啊,解決了我一個(gè)大問(wèn)題,上學(xué)的時(shí)候沒(méi)好好學(xué),現(xiàn)在要用才搞懂了!
          2013-09-08 20:23 | Ice_Xue

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)[未登錄](méi)  回復(fù)  更多評(píng)論   

          Select A.Name from A Left JOIN B ON A.id = B.id

          這個(gè)sql查詢列中沒(méi)有hobby,但是查詢結(jié)果中卻出現(xiàn)了hobby,確定不是sql寫錯(cuò)了?
          2014-11-14 10:41 | tiger

          # re: MySQL的 連接/聯(lián)結(jié)(Join)語(yǔ)法(原創(chuàng)!)[未登錄](méi)  回復(fù)  更多評(píng)論   

          STRAIGHT_JOIN是不是解釋錯(cuò)了?。。。是強(qiáng)制讀取左邊的表
          STRAIGHT_JOIN is similar to JOIN, except that the left table is always read before the right table. This can be used for those (few) cases for which the join optimizer puts the tables in the wrong order.
          在左表數(shù)據(jù)量小,但優(yōu)化器順序錯(cuò)誤先讀右表的情況下,強(qiáng)制先讀左表吧。。。
          2016-01-08 16:29 | null
          主站蜘蛛池模板: 宜兰县| 平定县| 瓮安县| 永和县| 怀远县| 驻马店市| 依兰县| 壤塘县| 宁晋县| 鲁山县| 仁怀市| 彭州市| 香河县| 包头市| 汤原县| 通辽市| 高碑店市| 无锡市| 调兵山市| 新建县| 淮安市| 城固县| 双桥区| 德清县| 九龙城区| 治县。| 图木舒克市| 鲁山县| 北京市| 陆川县| 鹿泉市| 桂林市| 收藏| 无棣县| 会理县| 曲水县| 中超| 长治市| 珲春市| 蕉岭县| 上林县|