一、多表連接類(lèi)型
1. 笛卡爾積(交叉連接)
在MySQL中可以為CROSS JOIN或者省略CROSS即JOIN婉徘,或者使用',' 如:
SELECT * FROM table1 CROSS JOIN table2
SELECT * FROM table1 JOIN table2
SELECT * FROM table1,table2
SELECT * FROM users CROSS JOIN articles;
SELECT * FROM users JOIN articles;
SELECT * FROM users, articles;
由于其返回的結(jié)果為被連接的兩個(gè)數(shù)據(jù)表的乘積,因此當(dāng)有WHERE, ON或USING條件的時(shí)候一般不建議使用咐汞,因?yàn)楫?dāng)數(shù)據(jù)表項(xiàng)目太多的時(shí)候盖呼,會(huì)非常慢。一般使用LEFT [OUTER] JOIN或者RIGHT [OUTER] JOIN
2. 內(nèi)連接INNER JOIN
在MySQL中把INNER JOIN叫做等值連接化撕,即需要指定等值連接條件在MySQL中CROSS和INNER JOIN被劃分在一起塌计。
SELECT * FROM users as u INNER JOIN articles as a where u.id = a.user_id
3. MySQL中的外連接
分為左外連接和右連接,即除了返回符合連接條件的結(jié)果之外侯谁,還要返回左表(左連接)或者右表(右連接)中不符合連接條件的結(jié)果锌仅,相對(duì)應(yīng)的使用NULL對(duì)應(yīng)。
例子:
users表:
+----+----------+----------+--------------------+
| id | username | password | email |
+----+----------+----------+--------------------+
| 1 | junxi | 123 | xinlei3166@126.com |
| 2 | tangtang | 456 | xinlei3166@126.com |
| 3 | ceshi3 | 456 | ceshi3@11.com |
| 4 | ceshi4 | 456 | ceshi4@qq.com |
| 5 | ceshi3 | 456 | ceshi3@11.com |
| 6 | ceshi4 | 456 | ceshi4@qq.com |
| 7 | ceshi3 | 456 | ceshi3@11.com |
| 8 | ceshi4 | 456 | ceshi4@qq.com |
| 9 | ceshi3 | 333 | ceshi3@11.com |
| 10 | ceshi4 | 444 | ceshi4@qq.com |
| 11 | ceshi3 | 333 | ceshi3@11.com |
| 12 | ceshi4 | 444 | ceshi4@qq.com |
+----+----------+----------+--------------------+
userinfos表:
+----+-------+--------+-------------+----------------+---------+
| id | name | qq | phone | link | user_id |
+----+-------+--------+-------------+----------------+---------+
| 1 | 君惜 | 666666 | 16616555188 | www.junxi.site | 1 |
| 2 | 糖糖 | 777777 | 17717555177 | www.weizhi.com | 2 |
| 3 | 測(cè)試3 | 333333 | 13313333177 | www.ceshi3.com | 3 |
+----+-------+--------+-------------+----------------+---------+
SQL語(yǔ)句:
SELECT * FROM users as u LEFT JOIN userinfos as i on u.id = i.user_id;
執(zhí)行結(jié)果:
+----+----------+----------+--------------------+------+-------+--------+-------------+----------------+---------+
| id | username | password | email | id | name | qq | phone | link | user_id |
+----+----------+----------+--------------------+------+-------+--------+-------------+----------------+---------+
| 1 | junxi | 123 | xinlei3166@126.com | 1 | 君惜 | 666666 | 16616555188 | www.junxi.site | 1 |
| 2 | tangtang | 456 | xinlei3166@126.com | 2 | 糖糖 | 777777 | 17717555177 | www.weizhi.com | 2 |
| 3 | ceshi3 | 456 | ceshi3@11.com | 3 | 測(cè)試3 | 333333 | 13313333177 | www.ceshi3.com | 3 |
| 4 | ceshi4 | 456 | ceshi4@qq.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 5 | ceshi3 | 456 | ceshi3@11.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 6 | ceshi4 | 456 | ceshi4@qq.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 7 | ceshi3 | 456 | ceshi3@11.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 8 | ceshi4 | 456 | ceshi4@qq.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 9 | ceshi3 | 333 | ceshi3@11.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 10 | ceshi4 | 444 | ceshi4@qq.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 11 | ceshi3 | 333 | ceshi3@11.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 12 | ceshi4 | 444 | ceshi4@qq.com | NULL | NULL | NULL | NULL | NULL | NULL |
+----+----------+----------+--------------------+------+-------+--------+-------------+----------------+---------+
分析:
而users表中的id大于3的用戶(hù)在userinfos中沒(méi)有相應(yīng)的紀(jì)錄墙贱,但是卻出現(xiàn)在了結(jié)果集中
因?yàn)楝F(xiàn)在是left join热芹,所有的工作以left為準(zhǔn).
結(jié)果1,2惨撇,3都是既在左表又在右表的紀(jì)錄4, 5, 6, 7, 8, 9, 10, 11, 12是只在左表伊脓,不在右表的紀(jì)錄
工作原理:
從左表讀出一條,選出所有與on匹配的右表紀(jì)錄(n條)進(jìn)行連接魁衙,形成n條紀(jì)錄(包括重復(fù)的行)报腔,如果右邊沒(méi)有與on條件匹配的表,那連接的字段都是null.然后繼續(xù)讀下一條剖淀。
引申:
我們可以用右表沒(méi)有on匹配則顯示null的規(guī)律, 來(lái)找出所有在左表纯蛾,不在右表的紀(jì)錄, 注意用來(lái)判斷的那列必須聲明為not null的纵隔。
如:
SQL:
(注意:
1.列值為null應(yīng)該用is null 而不能用=NULL
2.這里i.user_id 列必須聲明為 NOT NULL 的.
)
SELECT * FROM users as u LEFT JOIN userinfos as i on u.id = i.user_id WHERE i.user_id is NULL;
執(zhí)行結(jié)果:
+----+----------+----------+---------------+------+------+------+-------+------+---------+
| id | username | password | email | id | name | qq | phone | link | user_id |
+----+----------+----------+---------------+------+------+------+-------+------+---------+
| 4 | ceshi4 | 456 | ceshi4@qq.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 5 | ceshi3 | 456 | ceshi3@11.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 6 | ceshi4 | 456 | ceshi4@qq.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 7 | ceshi3 | 456 | ceshi3@11.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 8 | ceshi4 | 456 | ceshi4@qq.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 9 | ceshi3 | 333 | ceshi3@11.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 10 | ceshi4 | 444 | ceshi4@qq.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 11 | ceshi3 | 333 | ceshi3@11.com | NULL | NULL | NULL | NULL | NULL | NULL |
| 12 | ceshi4 | 444 | ceshi4@qq.com | NULL | NULL | NULL | NULL | NULL | NULL |
+----+----------+----------+---------------+------+------+------+-------+------+---------+
一般用法:
a. LEFT [OUTER] JOIN:
除了返回符合連接條件的結(jié)果之外翻诉,還需要顯示左表中不符合連接條件的數(shù)據(jù)列炮姨,相對(duì)應(yīng)使用NULL對(duì)應(yīng)
SELECT column_name FROM table1 LEFT [OUTER] JOIN table2 ON table1.column=table2.column
b. RIGHT [OUTER] JOIN:
RIGHT與LEFT JOIN相似不同的僅僅是除了顯示符合連接條件的結(jié)果之外,還需要顯示右表中不符合連接條件的數(shù)據(jù)列碰煌,相應(yīng)使用NULL對(duì)應(yīng)
SELECT column_name FROM table1 RIGHT [OUTER] JOIN table2 ON table1.column=table2.column
Tips:
- on a.c1 = b.c1 等同于 using(c1)
- INNER JOIN 和 , (逗號(hào)) 在語(yǔ)義上是等同的
- 當(dāng) MySQL 在從一個(gè)表中檢索信息時(shí)舒岸,你可以提示它選擇了哪一個(gè)索引。
如果 EXPLAIN 顯示 MySQL 使用了可能的索引列表中錯(cuò)誤的索引芦圾,這個(gè)特性將是很有用的蛾派。
通過(guò)指定 USE INDEX (key_list),你可以告訴 MySQL 使用可能的索引中最合適的一個(gè)索引在表中查找記錄行个少。
可選的二選一句法 IGNORE INDEX (key_list) 可被用于告訴 MySQL 不使用特定的索引洪乍。如:mysql> SELECT * FROM table1 USE INDEX (key1,key2) WHERE key1=1 AND key2=2 AND key3=3; mysql> SELECT * FROM table1 IGNORE INDEX (key3) WHERE key1=1 AND key2=2 AND key3=3;
二、表連接的約束條件
添加顯示條件WHERE, ON, USING
1. WHERE子句
SELECT * FROM table1,table2 WHERE table1.id=table2.id;
SELECT * FROM users, userinfos WHERE users.id=userinfos.user_id;
2. ON
SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id;
SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id LEFT JOIN table3 ON table2.id=table3.id;
SELECT * FROM users LEFT JOIN articles ON users.id = articles.user_id;
SELECT * FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id;
3. USING子句稍算,如果連接的兩個(gè)表連接條件的兩個(gè)列具有相同的名字的話可以使用USING
例如:
SELECT FROM LEFT JOIN USING ()
連接多于兩個(gè)表的情況舉例:
SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id;
執(zhí)行結(jié)果:
mysql> SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id;
+----------+-------+------------+
| username | name | title |
+----------+-------+------------+
| junxi | 君惜 | 中國(guó)有嘻哈 |
| tangtang | 糖糖 | 星光大道 |
| ceshi3 | 測(cè)試3 | 平凡的真諦 |
| junxi | 君惜 | python進(jìn)階 |
| ceshi3 | NULL | NULL |
| ceshi3 | NULL | NULL |
或者
SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id WHERE (articles.user_id IS NOT NULL AND userinfos.user_id IS NOT NULL);
執(zhí)行結(jié)果:
mysql> SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id WHERE (articles.user_id IS NOT NULL AND userinfos.user_
id IS NOT NULL);
+----------+-------+------------+
| username | name | title |
+----------+-------+------------+
| junxi | 君惜 | 中國(guó)有嘻哈 |
| tangtang | 糖糖 | 星光大道 |
| ceshi3 | 測(cè)試3 | 平凡的真諦 |
| junxi | 君惜 | python進(jìn)階 |
+----------+-------+------------+
或者
SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id WHERE (userinfos.name = '君惜');
執(zhí)行結(jié)果:
mysql> SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id WHERE (userinfos.name = '君惜');
+----------+------+------------+
| username | name | title |
+----------+------+------------+
| junxi | 君惜 | 中國(guó)有嘻哈 |
| junxi | 君惜 | python進(jìn)階 |
+----------+------+------------+
另外需要注意的地方 在MySQL中涉及到多表查詢(xún)的時(shí)候典尾,需要根據(jù)查詢(xún)的情況役拴,想好使用哪種連接方式效率更高糊探。
- 交叉連接(笛卡爾積)或者內(nèi)連接 [INNER | CROSS] JOIN
- 左外連接LEFT [OUTER] JOIN或者右外連接RIGHT [OUTER] JOIN 注意指定連接條件WHERE, ON,USING.
三河闰、MySQL如何優(yōu)化LEFT JOIN和RIGHT JOIN
在MySQL中科平,A LEFT JOIN B join_condition執(zhí)行過(guò)程如下:
1)· 根據(jù)表A和A依賴(lài)的所有表設(shè)置表B。
2)· 根據(jù)LEFT JOIN條件中使用的所有表(除了B)設(shè)置表A姜性。
3)· LEFT JOIN條件用于確定如何從表B搜索行瞪慧。(換句話說(shuō),不使用WHERE子句中的任何條件)部念。
4)· 可以對(duì)所有標(biāo)準(zhǔn)連接進(jìn)行優(yōu)化弃酌,只是只有從它所依賴(lài)的所有表讀取的表例外。如果出現(xiàn)循環(huán)依賴(lài)關(guān)系儡炼,MySQL提示出現(xiàn)一個(gè)錯(cuò)誤妓湘。
5)· 進(jìn)行所有標(biāo)準(zhǔn)WHERE優(yōu)化。
6)· 如果A中有一行匹配WHERE子句乌询,但B中沒(méi)有一行匹配ON條件榜贴,則生成另一個(gè)B行,其中所有列設(shè)置為NULL妹田。
7)· 如果使用LEFT JOIN找出在某些表中不存在的行唬党,并且進(jìn)行了下面的測(cè)試:WHERE部分的col_name IS NULL,其中col_name是一個(gè)聲明為 NOT NULL的列鬼佣,MySQL找到匹配LEFT JOIN條件的一個(gè)行后停止(為具體的關(guān)鍵字組合)搜索其它行驶拱。
RIGHT JOIN的執(zhí)行類(lèi)似LEFT JOIN,只是表的角色反過(guò)來(lái)晶衷。
連接優(yōu)化器計(jì)算表應(yīng)連接的順序屯烦。LEFT JOIN和STRAIGHT_JOIN強(qiáng)制的表讀順序可以幫助連接優(yōu)化器更快地工作坷随,因?yàn)闄z查的表交換更少。請(qǐng)注意這說(shuō)明如果執(zhí)行下面類(lèi)型的查詢(xún)驻龟,MySQL進(jìn)行全掃描b温眉,因?yàn)長(zhǎng)EFT JOIN強(qiáng)制它在d之前讀取:
SELECT * FROM a,b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) WHERE b.key=d.key;
在這種情況下修復(fù)時(shí)用a的相反順序翁狐,b列于FROM子句中:
SELECT * FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) WHERE b.key=d.key;
MySQL可以進(jìn)行下面的LEFT JOIN優(yōu)化:如果對(duì)于產(chǎn)生的NULL行类溢,WHERE條件總為假,LEFT JOIN變?yōu)槠胀?lián)接露懒。
例如闯冷,在下面的查詢(xún)中如果t2.column1為NULL,WHERE 子句將為false:
SELECT * FROM t1 LEFT JOIN t2 ON (column1) WHERE t2.column2=5;
因此懈词,可以安全地將查詢(xún)轉(zhuǎn)換為普通聯(lián)接:
SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1;
這樣可以更快蛇耀,因?yàn)槿绻梢允共樵?xún)更佳,MySQL可以在表t1之前使用表t2坎弯。為了強(qiáng)制使用表順序纺涤,使用RIGHT_JOIN。