成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

一起聊聊MySQL基礎(chǔ)之連接查詢

本篇文章給大家?guī)砹岁P(guān)于mysql中連接查詢的相關(guān)知識,其中包括內(nèi)連接、外連接、多表連接以及子查詢的相關(guān)問題,希望對大家有幫助。

一起聊聊MySQL基礎(chǔ)之連接查詢

再次認(rèn)識關(guān)系表

我們之前一直使用student_infostudent_score兩個(gè)表來分別存儲學(xué)生的基本信息和學(xué)生的成績信息,其實(shí)合并成一張表也不是不可以,假設(shè)將兩張表合并后的新表名稱為student_merge,那它應(yīng)該長這樣:

student_merge表

number name sex id_number department major enrollment_time subject score
20180101 杜子騰 158177199901044792 計(jì)算機(jī)學(xué)院 計(jì)算機(jī)科學(xué)與工程 2018-09-01 母豬的產(chǎn)后護(hù)理 78
20180101 杜子騰 158177199901044792 計(jì)算機(jī)學(xué)院 計(jì)算機(jī)科學(xué)與工程 2018-09-01 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備 88
20180102 杜琦燕 151008199801178529 計(jì)算機(jī)學(xué)院 計(jì)算機(jī)科學(xué)與工程 2018-09-01 母豬的產(chǎn)后護(hù)理 100
20180102 杜琦燕 151008199801178529 計(jì)算機(jī)學(xué)院 計(jì)算機(jī)科學(xué)與工程 2018-09-01 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備 98
20180103 范統(tǒng) 17156319980116959X 計(jì)算機(jī)學(xué)院 軟件工程 2018-09-01 母豬的產(chǎn)后護(hù)理 59
20180103 范統(tǒng) 17156319980116959X 計(jì)算機(jī)學(xué)院 軟件工程 2018-09-01 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備 61
20180104 史珍香 141992199701078600 計(jì)算機(jī)學(xué)院 軟件工程 2018-09-01 母豬的產(chǎn)后護(hù)理 55
20180104 史珍香 141992199701078600 計(jì)算機(jī)學(xué)院 軟件工程 2018-09-01 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備 46
20180105 范劍 181048200008156368 航天學(xué)院 飛行器設(shè)計(jì) 2018-09-01 NULL NULL
20180106 朱逸群 197995199801078445 航天學(xué)院 電子信息 2018-09-01 NULL NULL

有了這個(gè)合并后的表,我們就可以在一個(gè)查詢語句中既查詢到學(xué)生的基本信息,也查詢到學(xué)生的成績信息,比如這個(gè)查詢語句:

SELECT number, name, major, subject, score FROM student_merge;

其中查詢列表處的namemajor屬于學(xué)生的基本信息,subjectscore屬于學(xué)生的成績信息,而number既屬于成績信息也屬于基本信息,我們可以在一個(gè)對student_merge表的查詢語句中很輕松的把這些信息都查詢出來。但是別忘了一個(gè)學(xué)生可能會(huì)有很多門學(xué)科的成績信息,也就是說每當(dāng)我們想為一個(gè)學(xué)生增加一門學(xué)科的成績信息時(shí),我們必須把他的基本信息再抄一遍,這種同一個(gè)學(xué)生的基本信息被冗余存儲會(huì)帶來下邊的問題:

  • 問題一:浪費(fèi)存儲空間。

  • 問題二:當(dāng)修改某個(gè)學(xué)生的基本信息時(shí)必須修改多處,很容易造成信息的不一致,增大維護(hù)的困難。

所以為了盡可能少的存儲冗余信息,一開始我們就把這個(gè)所謂的student_merge表拆分成了student_infostudent_score表,但是這兩張表之間有某種關(guān)系作為紐帶,這里的某種關(guān)系指的就是兩個(gè)表都擁有的number列。

連接的概念

拆分之后的表的確解決了數(shù)據(jù)冗余問題,但是查詢數(shù)據(jù)卻成了一個(gè)問題。截至目前為止,在我們介紹的查詢方式中,查詢結(jié)果集只能是一個(gè)表中的一個(gè)列或者多個(gè)列,也就是說到目前為止還沒有一種可以在一條查詢語句中把某個(gè)學(xué)生的numbernamemajorsubjectscore這幾個(gè)信息都查詢出來的方式。

小貼士: 雖然我們前邊介紹的子查詢可以在一個(gè)查詢語句中涉及到多個(gè)表,但是整個(gè)查詢語句最終產(chǎn)生的結(jié)果集還是用來展示外層查詢的結(jié)果,子查詢的結(jié)果只是被當(dāng)作中間結(jié)果來使用。

時(shí)代在召喚一種可以在一個(gè)查詢語句結(jié)果集中展示多個(gè)表的信息的方式,連接查詢承擔(dān)了這個(gè)艱巨的歷史使命。當(dāng)然,為了故事的順利發(fā)展,我們先建立兩個(gè)簡單的表并給它們填充一點(diǎn)數(shù)據(jù):

mysql> CREATE TABLE t1 (m1 int, n1 char(1)); Query OK, 0 rows affected (0.02 sec)  mysql> CREATE TABLE t2 (m2 int, n2 char(1)); Query OK, 0 rows affected (0.02 sec)  mysql> INSERT INTO t1 VALUES(1, 'a'), (2, 'b'), (3, 'c'); Query OK, 3 rows affected (0.00 sec) Records: 3  Duplicates: 0  Warnings: 0  mysql> INSERT INTO t2 VALUES(2, 'b'), (3, 'c'), (4, 'd'); Query OK, 3 rows affected (0.00 sec) Records: 3  Duplicates: 0  Warnings: 0  mysql>

我們成功建立了t1t2兩個(gè)表,這兩個(gè)表都有兩個(gè)列,一個(gè)是INT類型的,一個(gè)是CHAR(1)類型的,填充好數(shù)據(jù)的兩個(gè)表長這樣:

mysql> SELECT * FROM t1; +------+------+ | m1   | n1   | +------+------+ |    1 | a    | |    2 | b    | |    3 | c    | +------+------+ 3 rows in set (0.00 sec)  mysql> SELECT * FROM t2; +------+------+ | m2   | n2   | +------+------+ |    2 | b    | |    3 | c    | |    4 | d    | +------+------+ 3 rows in set (0.00 sec)  mysql>

連接的本質(zhì)就是把各個(gè)表中的記錄都取出來依次匹配的組合加入結(jié)果集并返回給用戶。我們把t1和t2兩個(gè)表連接起來的過程如下圖所示:

一起聊聊MySQL基礎(chǔ)之連接查詢

這個(gè)過程看起來就是把t1表的記錄和t2表的記錄連起來組成新的更大的記錄,所以這個(gè)查詢過程稱之為連接查詢。連接查詢的結(jié)果集中包含一個(gè)表中的每一條記錄與另一個(gè)表中的每一條記錄相互匹配的組合,像這樣的結(jié)果集就可以稱之為笛卡爾積。因?yàn)楸?code>t1中有3條記錄,表t2中也有3條記錄,所以這兩個(gè)表連接之后的笛卡爾積就有3×3=9行記錄。在MySQL中,連接查詢的語法也很隨意,只要在FROM語句后邊跟多個(gè)用逗號,隔開的表名就好了,比如我們把t1表和t2表連接起來的查詢語句可以寫成這樣:

mysql> SELECT * FROM t1, t2; +------+------+------+------+ | m1   | n1   | m2   | n2   | +------+------+------+------+ |    1 | a    |    2 | b    | |    2 | b    |    2 | b    | |    3 | c    |    2 | b    | |    1 | a    |    3 | c    | |    2 | b    |    3 | c    | |    3 | c    |    3 | c    | |    1 | a    |    4 | d    | |    2 | b    |    4 | d    | |    3 | c    |    4 | d    | +------+------+------+------+ 9 rows in set (0.00 sec)

查詢列表處的*代表從FROM語句后列出的表中選取每個(gè)列,上邊的查詢語句其實(shí)和下邊這幾種寫法都是等價(jià)的:

  • 寫法一:

    SELECT t1.m1, t1.n1, t2.m2, t2.n2 FROM t1, t2;

    這種寫法是將t1t2表中的列名都顯式的寫出來,也就是使用了列的全限定名。

  • 寫法二:

    SELECT m1, n1, m2, n2 FROM t1, t2;

    由于t1t2表中的列名并不重復(fù),所以沒有可能讓服務(wù)器懵逼的二義性,在查詢列表上直接使用列名也是可以的。

  • 寫法三:

    SELECT t1.*, t2.* FROM t1, t2;

    這種寫法意思就是查詢t1表的全部的列,t2表的全部的列。

連接過程簡介

如果我們樂意,我們可以連接任意數(shù)量張表,但是如果沒有任何限制條件的話,這些表連接起來產(chǎn)生的笛卡爾積可能是非常巨大的。比方說3個(gè)100行記錄的表連接起來產(chǎn)生的笛卡爾積就有100×100×100=1000000行數(shù)據(jù)!所以在連接的時(shí)候過濾掉特定記錄組合是有必要的,在連接查詢中的過濾條件可以分成兩種:

  • 涉及單表的條件

    這種只涉及單表的過濾條件我們之前都提到過一萬遍了,我們之前也一直稱為搜索條件,比如t1.m1 > 1是只針對t1表的過濾條件,t2.n2 < 'd'是只針對t2表的過濾條件。

  • 涉及兩表的條件

    這種過濾條件我們之前沒見過,比如t1.m1 = t2.m2t1.n1 > t2.n2等,這些條件中涉及到了兩個(gè)表,我們稍后會(huì)仔細(xì)分析這種過濾條件是如何使用的哈。

下邊我們就要看一下攜帶過濾條件的連接查詢的大致執(zhí)行過程了,比方說下邊這個(gè)查詢語句:

SELECT * FROM t1, t2 WHERE t1.m1 > 1 AND t1.m1 = t2.m2 AND t2.n2 < 'd';

在這個(gè)查詢中我們指明了這三個(gè)過濾條件:

  • t1.m1 > 1

  • t1.m1 = t2.m2

  • t2.n2 < 'd'

那么這個(gè)連接查詢的大致執(zhí)行過程如下:

  1. 首先確定第一個(gè)需要查詢的表,這個(gè)表稱之為驅(qū)動(dòng)表。此處假設(shè)使用t1作為驅(qū)動(dòng)表,那么就需要到t1表中找滿足t1.m1 > 1的記錄,符合這個(gè)條件的t1表記錄如下所示:

    +------+------+ | m1   | n1   | +------+------+ |    2 | b    | |    3 | c    | +------+------+ 2 rows in set (0.01 sec)

    我們可以看到,t1表中符合t1.m1 > 1的記錄有兩條。

  2. 上一步驟中從驅(qū)動(dòng)表每獲取到一條記錄,都需要到t2表中查找匹配的記錄,所謂匹配的記錄,指的是符合過濾條件的記錄。因?yàn)槭歉鶕?jù)t1表中的記錄去找t2表中的記錄,所以t2表也可以被稱之為被驅(qū)動(dòng)表。上一步驟從驅(qū)動(dòng)表中得到了2條記錄,也就意味著需要查詢2次t2表。此時(shí)涉及兩個(gè)表的列的過濾條件t1.m1 = t2.m2就派上用場了:

    • 對于從t1表種查詢得到的第一條記錄,也就是當(dāng)t1.m1 = 2, t1.n1 = 'b'時(shí),過濾條件t1.m1 = t2.m2就相當(dāng)于t2.m2 = 2,所以此時(shí)t2表相當(dāng)于有了t2.m2 = 2t2.n2 < 'd'這兩個(gè)過濾條件,然后到t2表中執(zhí)行單表查詢,將得到的記錄和從t1表中查詢得到的第一條記錄相組合得到下邊的結(jié)果:

      +------+------+------+------+ | m1   | n1   | m2   | n2   | +------+------+------+------+ |    2 | b    |    2 | b    | +------+------+------+------+
    • 對于從t1表種查詢得到的第二條記錄,也就是當(dāng)t1.m1 = 3, t1.n1 = 'c'時(shí),過濾條件t1.m1 = t2.m2就相當(dāng)于t2.m2 = 3,所以此時(shí)t2表相當(dāng)于有了t2.m2 = 3t2.n2 < 'd'這兩個(gè)過濾條件,然后到t2表中執(zhí)行單表查詢,將得到的記錄和從t1表中查詢得到的第二條記錄相組合得到下邊的結(jié)果:

      +------+------+------+------+ | m1   | n1   | m2   | n2   | +------+------+------+------+ |    3 | c    |    3 | c    | +------+------+------+------+

    所以整個(gè)連接查詢的執(zhí)行最后得到的結(jié)果集就是這樣:

    +------+------+------+------+ | m1   | n1   | m2   | n2   | +------+------+------+------+ |    2 | b    |    2 | b    | |    3 | c    |    3 | c    | +------+------+------+------+ 2 rows in set (0.00 sec)

從上邊兩個(gè)步驟可以看出來,我們上邊嘮叨的這個(gè)兩表連接查詢共需要查詢1次t1表,2次t2表。當(dāng)然這是在特定的過濾條件下的結(jié)果,如果我們把t1.m1 > 1這個(gè)條件去掉,那么從t1表中查出的記錄就有3條,就需要查詢3次t2表了。也就是說在兩表連接查詢中,驅(qū)動(dòng)表只需要查詢一次,被驅(qū)動(dòng)表可能會(huì)被查詢多次。

內(nèi)連接和外連接

了解了連接查詢的執(zhí)行過程之后,視角再回到我們的student_info表和student_score表。現(xiàn)在我們想在一個(gè)查詢語句中既查詢到學(xué)生的基本信息,也查詢到學(xué)生的成績信息,就需要進(jìn)行兩表連接了。連接過程就是從student_info表中取出記錄,在student_score表中查找number值相同的成績記錄,所以過濾條件就是student_info.number = student_score.number,整個(gè)查詢語句就是這樣:

mysql> SELECT student_info.number, name, major, subject, score FROM student_info, student_score WHERE student_info.number = student_score.number; +----------+-----------+--------------------------+-----------------------------+-------+ | number   | name      | major                    | subject                     | score | +----------+-----------+--------------------------+-----------------------------+-------+ | 20180101 | 杜子騰    | 計(jì)算機(jī)科學(xué)與工程         | 母豬的產(chǎn)后護(hù)理              |    78 | | 20180101 | 杜子騰    | 計(jì)算機(jī)科學(xué)與工程         | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    88 | | 20180102 | 杜琦燕    | 計(jì)算機(jī)科學(xué)與工程         | 母豬的產(chǎn)后護(hù)理              |   100 | | 20180102 | 杜琦燕    | 計(jì)算機(jī)科學(xué)與工程         | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    98 | | 20180103 | 范統(tǒng)      | 軟件工程                 | 母豬的產(chǎn)后護(hù)理              |    59 | | 20180103 | 范統(tǒng)      | 軟件工程                 | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    61 | | 20180104 | 史珍香    | 軟件工程                 | 母豬的產(chǎn)后護(hù)理              |    55 | | 20180104 | 史珍香    | 軟件工程                 | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    46 | +----------+-----------+--------------------------+-----------------------------+-------+ 8 rows in set (0.00 sec)  mysql>

小貼士: student_info表和student_score表都有number列,不過我們在上述查詢語句的查詢列表中只放置了student_info表的number列,這是因?yàn)槲覀兊倪^濾條件是student_info.number = student_score.number,從兩個(gè)表中取出的記錄的number列都相同,所以只需要放置一個(gè)表中的number列到查詢列表即可,也就是說我們把student_score.number放到查詢列表處也是可以滴~

從上述查詢結(jié)果中我們可以看到,各個(gè)同學(xué)對應(yīng)的各科成績就都被查出來了,可是有個(gè)問題,范劍朱逸群同學(xué),也就是學(xué)號為2018010520180106的同學(xué)因?yàn)槟承┰驔]有參加考試,所以在studnet_score表中沒有對應(yīng)的成績記錄。那如果老師想查看所有同學(xué)的考試成績,即使是缺考的同學(xué)也應(yīng)該展示出來,但是到目前為止我們介紹的連接查詢是無法完成這樣的需求的。我們稍微思考一下這個(gè)需求,其本質(zhì)是想:驅(qū)動(dòng)表中的記錄即使在被驅(qū)動(dòng)表中沒有匹配的記錄,也仍然需要加入到結(jié)果集。為了解決這個(gè)問題,就有了內(nèi)連接外連接的概念:

  • 對于內(nèi)連接的兩個(gè)表,驅(qū)動(dòng)表中的記錄在被驅(qū)動(dòng)表中找不到匹配的記錄,該記錄不會(huì)加入到最后的結(jié)果集,我們上邊提到的連接都是所謂的內(nèi)連接

  • 對于外連接的兩個(gè)表,驅(qū)動(dòng)表中的記錄即使在被驅(qū)動(dòng)表中沒有匹配的記錄,也仍然需要加入到結(jié)果集。

    MySQL中,根據(jù)選取驅(qū)動(dòng)表的不同,外連接仍然可以細(xì)分為2種:

    • 左外連接

      選取左側(cè)的表為驅(qū)動(dòng)表。

    • 右外連接

      選取右側(cè)的表為驅(qū)動(dòng)表。

可是這樣仍然存在問題,即使對于外連接來說,有時(shí)候我們也并不想把驅(qū)動(dòng)表的全部記錄都加入到最后的結(jié)果集。這就犯難了,有時(shí)候匹配失敗要加入結(jié)果集,有時(shí)候又不要加入結(jié)果集,這咋辦,有點(diǎn)兒愁啊。。。噫,把過濾條件分為兩種不就解決了這個(gè)問題了么,所以放在不同地方的過濾條件是有不同語義的:

  • WHERE子句中的過濾條件

    WHERE子句中的過濾條件就是我們平時(shí)見的那種,不論是內(nèi)連接還是外連接,凡是不符合WHERE子句中的過濾條件的記錄都不會(huì)被加入最后的結(jié)果集。

  • ON子句中的過濾條件

    對于外連接的驅(qū)動(dòng)表的記錄來說,如果無法在被驅(qū)動(dòng)表中找到匹配ON子句中的過濾條件的記錄,那么該記錄仍然會(huì)被加入到結(jié)果集中,對應(yīng)的被驅(qū)動(dòng)表記錄的各個(gè)字段使用NULL值填充。

    需要注意的是,這個(gè)ON子句是專門為外連接驅(qū)動(dòng)表中的記錄在被驅(qū)動(dòng)表找不到匹配記錄時(shí)應(yīng)不應(yīng)該把該記錄加入結(jié)果集這個(gè)場景下提出的,所以如果把ON子句放到內(nèi)連接中,MySQL會(huì)把它和WHERE子句一樣對待,也就是說:內(nèi)連接中的WHERE子句和ON子句是等價(jià)的。

一般情況下,我們都把只涉及單表的過濾條件放到WHERE子句中,把涉及兩表的過濾條件都放到ON子句中,我們也一般把放到ON子句中的過濾條件也稱之為連接條件

小貼士: 左外連接和右外連接簡稱左連接和右連接,所以下邊提到的左外連接和右外連接中的`外`字都用括號擴(kuò)起來,以表示這個(gè)字兒可有可無。

左(外)連接的語法

左(外)連接的語法還是挺簡單的,比如我們要把t1表和t2表進(jìn)行左外連接查詢可以這么寫:

SELECT * FROM t1 LEFT [OUTER] JOIN t2 ON 連接條件 [WHERE 普通過濾條件];

其中中括號里的OUTER單詞是可以省略的。對于LEFT JOIN類型的連接來說,我們把放在左邊的表稱之為外表或者驅(qū)動(dòng)表,右邊的表稱之為內(nèi)表或者被驅(qū)動(dòng)表。所以上述例子中t1就是外表或者驅(qū)動(dòng)表,t2就是內(nèi)表或者被驅(qū)動(dòng)表。需要注意的是,對于左(外)連接和右(外)連接來說,必須使用ON子句來指出連接條件。了解了左(外)連接的基本語法之后,再次回到我們上邊那個(gè)現(xiàn)實(shí)問題中來,看看怎樣寫查詢語句才能把所有的學(xué)生的成績信息都查詢出來,即使是缺考的考生也應(yīng)該被放到結(jié)果集中:

mysql> SELECT student_info.number, name, major, subject, score FROM student_info LEFT JOIN student_score ON student_info.number = student_score.number; +----------+-----------+--------------------------+-----------------------------+-------+ | number   | name      | major                    | subject                     | score | +----------+-----------+--------------------------+-----------------------------+-------+ | 20180101 | 杜子騰    | 計(jì)算機(jī)科學(xué)與工程         | 母豬的產(chǎn)后護(hù)理              |    78 | | 20180101 | 杜子騰    | 計(jì)算機(jī)科學(xué)與工程         | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    88 | | 20180102 | 杜琦燕    | 計(jì)算機(jī)科學(xué)與工程         | 母豬的產(chǎn)后護(hù)理              |   100 | | 20180102 | 杜琦燕    | 計(jì)算機(jī)科學(xué)與工程         | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    98 | | 20180103 | 范統(tǒng)      | 軟件工程                 | 母豬的產(chǎn)后護(hù)理              |    59 | | 20180103 | 范統(tǒng)      | 軟件工程                 | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    61 | | 20180104 | 史珍香    | 軟件工程                 | 母豬的產(chǎn)后護(hù)理              |    55 | | 20180104 | 史珍香    | 軟件工程                 | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    46 | | 20180105 | 范劍      | 飛行器設(shè)計(jì)               | NULL                        |  NULL | | 20180106 | 朱逸群    | 電子信息                 | NULL                        |  NULL | +----------+-----------+--------------------------+-----------------------------+-------+ 10 rows in set (0.00 sec)  mysql>

從結(jié)果集中可以看出來,雖然范劍朱逸群并沒有對應(yīng)的成績記錄,但是由于采用的是連接類型為左(外)連接,所以仍然把它放到了結(jié)果集中,只不過在對應(yīng)的成績記錄的各列使用NULL值填充而已。

右(外)連接的語法

右(外)連接和左(外)連接的原理是一樣一樣的,語法也只是把LEFT換成RIGHT而已:

SELECT * FROM t1 RIGHT [OUTER] JOIN t2 ON 連接條件 [WHERE 普通過濾條件];

只不過驅(qū)動(dòng)表是右邊的表,被驅(qū)動(dòng)表是左邊的表,具體就不嘮叨了。

內(nèi)連接的語法

內(nèi)連接和外連接的根本區(qū)別就是在驅(qū)動(dòng)表中的記錄不符合ON子句中的連接條件時(shí)不會(huì)把該記錄加入到最后的結(jié)果集,我們最開始嘮叨的那些連接查詢的類型都是內(nèi)連接。不過之前僅僅提到了一種最簡單的內(nèi)連接語法,就是直接把需要連接的多個(gè)表都放到FROM子句后邊。其實(shí)針對內(nèi)連接,MySQL提供了好多不同的語法,我們以t1t2表為例瞅瞅:

SELECT * FROM t1 [INNER | CROSS] JOIN t2 [ON 連接條件] [WHERE 普通過濾條件];

也就是說在MySQL中,下邊這幾種內(nèi)連接的寫法都是等價(jià)的:

  • SELECT * FROM t1 JOIN t2;

  • SELECT * FROM t1 INNER JOIN t2;

  • SELECT * FROM t1 CROSS JOIN t2;

上邊的這些寫法和直接把需要連接的表名放到FROM語句之后,用逗號,分隔開的寫法是等價(jià)的:

 SELECT * FROM t1, t2;

現(xiàn)在我們雖然介紹了很多種內(nèi)連接的書寫方式,不過熟悉一種就好了,這里我們推薦INNER JOIN的形式書寫內(nèi)連接(因?yàn)镮NNER JOIN語義很明確嘛,可以和LEFT JOIN和RIGHT JOIN很輕松的區(qū)分開)。這里需要注意的是,由于在內(nèi)連接中ON子句和WHERE子句是等價(jià)的,所以內(nèi)連接中不要求強(qiáng)制寫明ON子句。

我們前邊說過,連接的本質(zhì)就是把各個(gè)連接表中的記錄都取出來依次匹配的組合加入結(jié)果集并返回給用戶。不論哪個(gè)表作為驅(qū)動(dòng)表,兩表連接產(chǎn)生的笛卡爾積肯定是一樣的。而對于內(nèi)連接來說,由于凡是不符合ON子句或WHERE子句中的條件的記錄都會(huì)被過濾掉,其實(shí)也就相當(dāng)于從兩表連接的笛卡爾積中把不符合過濾條件的記錄給踢出去,所以對于內(nèi)連接來說,驅(qū)動(dòng)表和被驅(qū)動(dòng)表是可以互換的,并不會(huì)影響最后的查詢結(jié)果。但是對于外連接來說,由于驅(qū)動(dòng)表中的記錄即使在被驅(qū)動(dòng)表中找不到符合ON子句連接條件的記錄也會(huì)被加入結(jié)果集,所以此時(shí)驅(qū)動(dòng)表和被驅(qū)動(dòng)表的關(guān)系就很重要了,也就是說左外連接和右外連接的驅(qū)動(dòng)表和被驅(qū)動(dòng)表不能輕易互換。

小結(jié)

上邊說了很多,給大家的感覺不是很直觀,我們直接把表t1和t2的三種連接方式寫在一起,這樣大家理解起來就很easy了:

mysql> SELECT * FROM t1 INNER JOIN t2 ON t1.m1 = t2.m2; +------+------+------+------+ | m1   | n1   | m2   | n2   | +------+------+------+------+ |    2 | b    |    2 | b    | |    3 | c    |    3 | c    | +------+------+------+------+ 2 rows in set (0.00 sec)  mysql> SELECT * FROM t1 LEFT JOIN t2 ON t1.m1 = t2.m2; +------+------+------+------+ | m1   | n1   | m2   | n2   | +------+------+------+------+ |    2 | b    |    2 | b    | |    3 | c    |    3 | c    | |    1 | a    | NULL | NULL | +------+------+------+------+ 3 rows in set (0.00 sec)  mysql> SELECT * FROM t1 RIGHT JOIN t2 ON t1.m1 = t2.m2; +------+------+------+------+ | m1   | n1   | m2   | n2   | +------+------+------+------+ |    2 | b    |    2 | b    | |    3 | c    |    3 | c    | | NULL | NULL |    4 | d    | +------+------+------+------+ 3 rows in set (0.00 sec)

連接查詢產(chǎn)生的結(jié)果集就好像把散布到兩個(gè)表中的信息被重新粘貼到了一個(gè)表,這個(gè)粘貼后的結(jié)果集可以方便我們分析數(shù)據(jù),就不用老是兩個(gè)表對照的看了。

多表連接

上邊說過,如果我們樂意的話可以連接任意數(shù)量的表,我們再來創(chuàng)建一個(gè)簡單的t3表:

mysql> CREATE TABLE t3 (m3 int, n3 char(1)); ERROR 1050 (42S01): Table 't3' already exists mysql> INSERT INTO t3 VALUES(3, 'c'), (4, 'd'), (5, 'e'); Query OK, 3 rows affected (0.01 sec) Records: 3  Duplicates: 0  Warnings: 0  mysql>

t1t2表的結(jié)構(gòu)一樣,也是一個(gè)INT列,一個(gè)CHAR(1)列,現(xiàn)在我們看一下把這3個(gè)表連起來的樣子:

mysql> SELECT * FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.m1 = t2.m2 AND t1.m1 = t3.m3; +------+------+------+------+------+------+ | m1   | n1   | m2   | n2   | m3   | n3   | +------+------+------+------+------+------+ |    3 | c    |    3 | c    |    3 | c    | +------+------+------+------+------+------+ 1 row in set (0.00 sec)  mysql>

其實(shí)上邊的查詢語句也可以寫成這樣,用哪個(gè)取決于你的心情:

SELECT * FROM t1 INNER JOIN t2 ON t1.m1 = t2.m2 INNER JOIN t3 ON t1.m1 = t3.m3;

這個(gè)查詢的執(zhí)行過程用偽代碼表示一下就是這樣:

for each row in t1 {      for each row in t2 which satisfies t1.m1 = t2.m2 {                  for each row in t3 which satisfies t1.m1 = t3.m3 {             send to client;         }     } }

其實(shí)不管是多少個(gè)表的連接,本質(zhì)上就是各個(gè)表的記錄在符合過濾條件下的自由組合。

表的別名

我們前邊曾經(jīng)為列命名過別名,比如說這樣:

mysql> SELECT number AS xuehao FROM student_info; +----------+ | xuehao   | +----------+ | 20180104 | | 20180102 | | 20180101 | | 20180103 | | 20180105 | | 20180106 | +----------+ 6 rows in set (0.00 sec)  mysql>

我們可以把列的別名用在ORDER BYGROUP BY等子句上,比如這樣:

mysql> SELECT number AS xuehao FROM student_info ORDER BY xuehao DESC; +----------+ | xuehao   | +----------+ | 20180106 | | 20180105 | | 20180104 | | 20180103 | | 20180102 | | 20180101 | +----------+ 6 rows in set (0.00 sec)  mysql>

與列的別名類似,我們也可以為表來定義別名,格式與定義列的別名一致,都是用空白字符或者AS隔開,這個(gè)在表名特別長的情況下可以讓語句表達(dá)更清晰一些,比如這樣:

mysql> SELECT s1.number, s1.name, s1.major, s2.subject, s2.score FROM student_info AS s1 INNER JOIN student_score AS s2 WHERE s1.number = s2.number; +----------+-----------+--------------------------+-----------------------------+-------+ | number   | name      | major                    | subject                     | score | +----------+-----------+--------------------------+-----------------------------+-------+ | 20180101 | 杜子騰    | 計(jì)算機(jī)科學(xué)與工程         | 母豬的產(chǎn)后護(hù)理              |    78 | | 20180101 | 杜子騰    | 計(jì)算機(jī)科學(xué)與工程         | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    88 | | 20180102 | 杜琦燕    | 計(jì)算機(jī)科學(xué)與工程         | 母豬的產(chǎn)后護(hù)理              |   100 | | 20180102 | 杜琦燕    | 計(jì)算機(jī)科學(xué)與工程         | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    98 | | 20180103 | 范統(tǒng)      | 軟件工程                 | 母豬的產(chǎn)后護(hù)理              |    59 | | 20180103 | 范統(tǒng)      | 軟件工程                 | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    61 | | 20180104 | 史珍香    | 軟件工程                 | 母豬的產(chǎn)后護(hù)理              |    55 | | 20180104 | 史珍香    | 軟件工程                 | 論薩達(dá)姆的戰(zhàn)爭準(zhǔn)備          |    46 | +----------+-----------+--------------------------+-----------------------------+-------+ 8 rows in set (0.00 sec)  mysql>

這個(gè)例子中,我們在FROM子句中給student_info定義了一個(gè)別名s1student_score定義了一個(gè)別名s2,那么在整個(gè)查詢語句的其他地方就可以引用這個(gè)別名來替代該表本身的名字了。

自連接

我們上邊說的都是多個(gè)不同的表之間的連接,其實(shí)同一個(gè)表也可以進(jìn)行連接。比方說我們可以對兩個(gè)t1表來生成笛卡爾積,就像這樣:

mysql> SELECT * FROM t1, t1; ERROR 1066 (42000): Not unique table/alias: 't1' mysql>

咦,報(bào)了個(gè)錯(cuò),這是因?yàn)樵O(shè)計(jì)MySQL的大叔不允許FROM子句中出現(xiàn)相同的表名。我們這里需要的是兩張一模一樣的t1表進(jìn)行連接,為了把兩個(gè)一樣的表區(qū)分一下,需要為表定義別名。比如這樣:

mysql> SELECT * FROM t1 AS table1, t1 AS table2; +------+------+------+------+ | m1   | n1   | m1   | n1   | +------+------+------+------+ |    1 | a    |    1 | a    | |    2 | b    |    1 | a    | |    3 | c    |    1 | a    | |    1 | a    |    2 | b    | |    2 | b    |    2 | b    | |    3 | c    |    2 | b    | |    1 | a    |    3 | c    | |    2 | b    |    3 | c    | |    3 | c    |    3 | c    | +------+------+------+------+ 9 rows in set (0.00 sec)  mysql>

這里相當(dāng)于我們?yōu)?code>t1表定義了兩個(gè)副本,一個(gè)是table1,另一個(gè)是table2,這里的連接過程就不贅述了,大家把它們認(rèn)為是不同的表就好了。由于被連接的表其實(shí)是源自同一個(gè)表,所以這種連接也稱為自連接。我們看一下這個(gè)自連接的現(xiàn)實(shí)意義,比方說我們想查看與'史珍香'相同專業(yè)的學(xué)生有哪些,可以這么寫:

mysql> SELECT s2.number, s2.name, s2.major FROM student_info AS s1 INNER JOIN student_info AS s2 WHERE s1.major = s2.major AND s1.name = '史珍香' ; +----------+-----------+--------------+ | number   | name      | major        | +----------+-----------+--------------+ | 20180103 | 范統(tǒng)      | 軟件工程     | | 20180104 | 史珍香    | 軟件工程     | +----------+-----------+--------------+ 2 rows in set (0.01 sec)  mysql>

s1s2都可以看作是student_info表的一份副本,我們可以這樣理解這個(gè)查詢:

  • 根據(jù)s1.name = '史珍香'搜索條件過濾s1表,可以得到該同學(xué)的基本信息:

    +----------+-----------+------+--------------------+-----------------+--------------+-----------------+ | number   | name      | sex  | id_number          | department      | major        | enrollment_time | +----------+-----------+------+--------------------+-----------------+--------------+-----------------+ | 20180104 | 史珍香    | 女   | 141992199701078600 | 計(jì)算機(jī)學(xué)院      | 軟件工程     | 2018-09-01      | +----------+-----------+------+--------------------+-----------------+--------------+-----------------+
  • 因?yàn)橥ㄟ^查詢s1表,得到了'史珍香'所在的專業(yè)其實(shí)是'軟件工程',接下來就應(yīng)該查詢s2表了,查詢s2表的時(shí)候的過濾條件s1.major = s2.major就相當(dāng)于s2.major = '軟件工程',于是查詢到2條記錄:

    +----------+-----------+------+--------------------+-----------------+--------------+-----------------+ | number   | name      | sex  | id_number          | department      | major        | enrollment_time | +----------+-----------+------+--------------------+-----------------+--------------+-----------------+ | 20180103 | 范統(tǒng)      | 男   | 17156319980116959X | 計(jì)算機(jī)學(xué)院      | 軟件工程     | 2018-09-01      | | 20180104 | 史珍香    | 女   | 141992199701078600 | 計(jì)算機(jī)學(xué)院      | 軟件工程     | 2018-09-01      | +----------+-----------+------+--------------------+-----------------+--------------+-----------------+

    而我們只需要s2表的numbernamemajor這3個(gè)列的數(shù)據(jù),所以最終的結(jié)果就長這樣:

    +----------+-----------+--------------+ | number   | name      | major        | +----------+-----------+--------------+ | 20180103 | 范統(tǒng)      | 軟件工程     | | 20180104 | 史珍香    | 軟件工程     | +----------+-----------+--------------+

連接查詢與子查詢的轉(zhuǎn)換

有的查詢需求既可以使用連接查詢解決,也可以使用子查詢解決,比如

SELECT * FROM student_score WHERE number IN (SELECT number FROM student_info WHERE major = '計(jì)算機(jī)科學(xué)與工程');

這個(gè)子查詢就可以被替換:

SELECT s2.* FROM student_info AS s1 INNER JOIN student_score AS s2 WHERE s1.number = s2.number AND s1.major = '計(jì)算機(jī)科學(xué)與工程';

大家在實(shí)際使用時(shí)可以按照自己的習(xí)慣來書寫查詢語句。

小貼士: MySQL服務(wù)器在內(nèi)部可能將子查詢轉(zhuǎn)換為連接查詢來處理,當(dāng)然也可能用別的方式來處理,不過對于我們剛?cè)腴T的小白來說,這些都不重要,知道這個(gè)語句會(huì)把哪些信息查出來就好了!

推薦學(xué)習(xí):mysql視頻教程

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
国产玉足榨精视频在线观看| 国产三级久久精品三级| 国产交换配乱婬视频| 国产美女mv一区二区竹| 公交车上摸到花蒂进去了视频| 成人永久免费高清视频在线观看| 国产成人乱码一二三区18| 精东传媒VS天美传媒合作| 免费人妻AV无码专区| 日韩欧美人妻一区二区三区| 亚州日本乱码一区二区三区| 夜夜高潮次次欢爽AV女| 国产AV激情久久无码天堂| 精品久久久久久狼人社区| 欧洲肉欲K8播放毛片护士报告| 水蜜桃成视频人在线看| 亚洲国产精品无码中文在线| 中文字幕在线不卡一区二区| 穿越后每天都在PIAPIA打脸| 久久精品成人亚洲另类欧美| 亲孑伦视频一区二区三区| 亚洲AV无码麻豆一区二区三区| 中文字幕肉感巨大的乳专区 | AV男人在线东京天堂| 国产激情一区二区三区| 两根硕大一起挤进小紧H共妻| 日韩人妻无码精品无码中文字幕| 亚洲国产制服丝袜先锋| 波多野结衣一区二区三区高清| 精品久久久久久无码人妻热| 少妇丰满爆乳被呻吟进入| 2022精品久久久久久中文字幕| 国产综合无码一区二区辣椒| 人妻无码久久中文字幕专区| 亚洲国产精品VA在线观看麻豆| 草莓视频下载APP| 久久久久亚洲AV片无码V| 日日狠狠久久偷偷色综合免费| 亚洲乱码无人区卡1卡2卡3| 国99精品无码一区二区三区| 精品久久久久久中文字幕202| 内射人妻无套中出无码| 四季AV无码专区AV浪潮| BRAZZERSHD欧美巨大| 久久天天躁狠狠躁夜夜AVAPP| 学渣含着学霸几巴的写作业视频| YSL千人千色T9T9T90| 精品国产一区二区三区久久| 看黄A大片日本真人视频直播| 強暴強姦AV正片一区二区三区| 少妇夜夜春夜夜爽试看视频| 亚洲一区在线观看XXX| 草草浮力地址线路①屁屁影院 | 十八18禁国产精品WWW| 亚洲国产成人久久一区WWW| AV天堂精品久久久久2| 和岳每晚弄的高潮嗷嗷叫| 人妻熟妇av又粗又爽| 亚洲AV永久无码精品主页| H纯肉无遮掩3D动漫在线观看| 狠狠色噜噜狠狠狠狠色综合网| 人妻少妇无码专视频在线| 亚洲人成网站999久久久综合| 波多野结衣AV高清一区二区三区 | 99久久精品费精品国产| 国产在线孕妇孕交| 人妻熟妇av又粗又爽| 少妇人妻精品一区二区三区| 亚洲AV永久无码精品表情包| FREE潄白的SEX性娇小HD| 黑鬼吊太大少妇尖叫| 午夜熟女插插XX免费视频| 孩交乱子XXXX高清影视| 宝宝两根就哭男男是不是太早了| 久久国国产免费999| 亚洲中文字幕在线第六区| 久久久久噜噜噜亚洲熟女综合| 野花高清在线观看免费3中文| 久久人妻AV无码中文专区| 又粗又黄又爽视频免费看| 免费观看人成影片| 99久久99久久精品国产片| 欧美性婬爽www视频播放| 宝宝好涨水快流出来免费视频| 日韩成人无码一区二区三区| 东北露脸46熟妇ⅩⅩXX| 玩弄丰满熟妇乱XXXXX性多毛| 国产看黄网站又黄又爽又色| 亚洲AV无码精品网站| 久久精品国产99精品国产2| 又湿又紧又大又爽A视频国产| 麻豆一区二区三区蜜桃免费| AV无码人妻一区二区三区牛牛| 人妻无码ΑV中文字幕琪琪布| 丁香花在线视频观看免费| 无码AVAV无码中文字幕| 孩交乱子XXXX高清影视| 夜夜高潮夜夜爽高清视频一| 女技师强制高潮18XXXX按摩| 按摩师用嘴亲我下面过程| 丝袜美腿一区二区三区| 国产尤物精品视频| 亚洲一区二区无码偷拍| 欧美黑人性暴力猛交喷水| 大学生酒店呻吟在线观看| 无人区码一码二码三码是什么 | 亚洲欧美成人中文日韩电影网站| 狼友AV永久网站在线观看| VIDEOS性饥渴| 四川丰满少妇A级毛片| 国模生殖欣赏337METCN| 一区二区三区精品视频免费播放| 欧美乱人伦人妻中文字幕| 疯狂做受XXXX高潮视频免费| 亚洲国产精品VA在线观看香蕉| 免费AV大片在线观看入口| 草莓视频下载APP| 性欧美长视频免费观看不卡| 久久影院午夜理论片无码| ZOOM与人马性ZOOM的区别| 无码精品一区二区三区在线| 久久精品国产99精品最新| WWWらだ天堂中文在线| 未满十八18禁止午夜免费网站| 九九精品99久久久香蕉| A级毛片免费观看完整| 天堂影院在线观看高清在线| 精品欧美一区二区在线观看 | 中中文日产幕无线码一区| 日韩人妻无码精品专区综合网 | 旧里番6080在线观看| 成年午夜免费韩国做受| 亚洲AV无码专区国产乱码DVD| 免费A级毛片无码免费视频APP| 丰满熟妇BBWBBWBBWBB| 亚洲乱码日产精品BD| 欧美性狂猛BBBBBBXXXXXX| 国产视频一区二区| 自拍偷在线精品自拍偷| 玩弄老太太的BBB| 老公和兄弟一前一后攻击| 大号BBVVBBW高潮| 亚洲色精品一区二区三AI女星| 欧洲老妇做爰XXXⅩ性活电影| 国产麻豆精品乱码一区| 中文有无人妻VS无码人妻激烈| 天堂中文资源在线最新版下载| 久久久久影院美女国产主播| 东京热加勒比无码视频| 亚洲一线产区二线产区区别在哪| 日产无人区一线二线三线观看 | JIZZ中国JIZZ在线观看| 亚洲AV无码精品色午夜| 欧洲无码一区二区三区在线观看| 国色天香一卡2卡三卡4卡乱码| AⅤ精品一区二区三区| 亚洲AV鲁丝一区二区三区| 欧美疯狂做受XXXX高潮| 国精产品一区二区三区有限| JEANASIS日本| 亚洲欧美成人一区二区三区| 色婷婷综合久久久久中文| 久久亚洲私人国产精品| 国产精品国产AV片国产| 97超碰人人人人人人少妇| 亚洲AV无码AV制服丝袜在线| 人人妻人人澡人人爽人人精品电影 | 国产欧美久久一区二区| chinese人妻无码人妻| 亚洲精品成A人在线观看| 日韩一区二区视频在线| 里番本子库绅士ACG全彩无码 | 色婷婷亚洲六月婷婷中文字幕 | 成人免费视频一区二区| 一区二区三区精品视频日本| 无遮挡又色又刺激的视频黄| 欧美精产国品一二三区别| 精品国产三级A∨在线无码| 粉嫩av.com| 69美女ⅩXXXXXXX19| 亚洲成AV人片在线观看无码不卡| 日韩精品无码一区二区三区不卡| 久久人人妻人人做人人爽| 国产美女精品一区二区三区 | YOUJIZZCOM中国熟妇| 艳妇乳肉豪妇荡乳ⅩXXOO| 香港三日本三级少妇三级2021| 人妻妺妺窝人体色WWW聚色窝| 久久久久久精品免费免费软件 | 国产清纯白嫩初高生在线观看| 锕锕锕锕锕锕~好湿WWW| 伊人色综合一区二区三区影院视频| 无码精品国产VA在线观看DVD| 欧美日韩国产精品自在自线| 久久久国产精品ⅤA麻豆百度| 国产精品一区二区香蕉 | 亚洲AV无码乱码| 四川骚妇无套内射舔了更爽| 人妻无码一区二区三区蜜桃视频 | 看国产一毛片在线看手机看|