您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關Mysq中JOIN有什么用的內容。小編覺得挺實用的,因此分享給大家做個參考。一起跟隨小編過來看看吧。
- JOIN語句的執行順序
- INNER/LEFT/RIGHT/FULL JOIN的區別
- ON和WHERE的區別
一個完整的SQL語句中會被拆分成多個子句,子句的執行過程中會產生虛擬表(vt),但是結果只返回最后一張虛擬表。從這個思路出發,我們試著理解一下JOIN查詢的執行過程并解答一些常見的問題。
如果之前對不同JOIN的執行結果沒有概念,可以結合這篇文章往下看
以下是JOIN查詢的通用結構
SELECT <row_list> FROM <left_table> <inner|left|right> JOIN <right_table> ON <join condition> WHERE <where_condition>
它的執行順序如下(SQL語句里第一個被執行的總是FROM子句):
下面用一個例子介紹一下上述聯表的過程(這個例子不是個好的實踐,只是為了說明join語法)
創建一個用戶信息表:
CREATE TABLE `user_info` ( `userid` int(11) NOT NULL, `name` varchar(255) NOT NULL, UNIQUE `userid` (`userid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
再創建一個用戶余額表:
CREATE TABLE `user_account` ( `userid` int(11) NOT NULL, `money` bigint(20) NOT NULL, UNIQUE `userid` (`userid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
隨便導入一些數據:
select * from user_info; +--------+------+ | userid | name | +--------+------+ | 1001 | x | | 1002 | y | | 1003 | z | | 1004 | a | | 1005 | b | | 1006 | c | | 1007 | d | | 1008 | e | +--------+------+ 8 rows in set (0.00 sec) select * from user_account; +--------+-------+ | userid | money | +--------+-------+ | 1001 | 22 | | 1002 | 30 | | 1003 | 8 | | 1009 | 11 | +--------+-------+ 4 rows in set (0.00 sec)
一共8個用戶有用戶名,4個用戶的賬戶有余額。
取出userid為1003的用戶姓名和余額,SQL如下:
SELECT i.name, a.money FROM user_info as i LEFT JOIN user_account as a ON i.userid = a.userid WHERE a.userid = 1003;
笛卡爾積操作后會返回兩張表中所有行的組合,左表user_info有8行,右表user_account有4行,生成的虛擬表vt1就是8*4=32行:
SELECT * FROM user_info as i LEFT JOIN user_account as a ON 1; +--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1001 | x | 1001 | 22 | | 1002 | y | 1001 | 22 | | 1003 | z | 1001 | 22 | | 1004 | a | 1001 | 22 | | 1005 | b | 1001 | 22 | | 1006 | c | 1001 | 22 | | 1007 | d | 1001 | 22 | | 1008 | e | 1001 | 22 | | 1001 | x | 1002 | 30 | | 1002 | y | 1002 | 30 | | 1003 | z | 1002 | 30 | | 1004 | a | 1002 | 30 | | 1005 | b | 1002 | 30 | | 1006 | c | 1002 | 30 | | 1007 | d | 1002 | 30 | | 1008 | e | 1002 | 30 | | 1001 | x | 1003 | 8 | | 1002 | y | 1003 | 8 | | 1003 | z | 1003 | 8 | | 1004 | a | 1003 | 8 | | 1005 | b | 1003 | 8 | | 1006 | c | 1003 | 8 | | 1007 | d | 1003 | 8 | | 1008 | e | 1003 | 8 | | 1001 | x | 1009 | 11 | | 1002 | y | 1009 | 11 | | 1003 | z | 1009 | 11 | | 1004 | a | 1009 | 11 | | 1005 | b | 1009 | 11 | | 1006 | c | 1009 | 11 | | 1007 | d | 1009 | 11 | | 1008 | e | 1009 | 11 | +--------+------+--------+-------+ 32 rows in set (0.00 sec)
ON i.userid = a.userid 過濾之后vt2如下:
+--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1001 | x | 1001 | 22 | | 1002 | y | 1002 | 30 | | 1003 | z | 1003 | 8 | +--------+------+--------+-------+
LEFT JOIN會將左表未出現在vt2的行插入進vt2,每一行的剩余字段將被填充為NULL,RIGHT JOIN同理
本例中用的是LEFT JOIN,所以會將左表user_info剩下的行都添上 生成表vt3:
+--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1001 | x | 1001 | 22 | | 1002 | y | 1002 | 30 | | 1003 | z | 1003 | 8 | | 1004 | a | NULL | NULL | | 1005 | b | NULL | NULL | | 1006 | c | NULL | NULL | | 1007 | d | NULL | NULL | | 1008 | e | NULL | NULL | +--------+------+--------+-------+
WHERE a.userid = 1003 生成表vt4:
+--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1003 | z | 1003 | 8 | +--------+------+--------+-------+
SELECT i.name, a.money 生成vt5:
+------+-------+ | name | money | +------+-------+ | z | 8 | +------+-------+
虛擬表vt5作為最終結果返回給客戶端
介紹完聯表的過程之后,我們看看常用JOIN的區別
拿上文的第三步添加外部行來舉例,若LEFT JOIN替換成INNER JOIN,則會跳過這一步,生成的表vt3與vt2一模一樣:
+--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1001 | x | 1001 | 22 | | 1002 | y | 1002 | 30 | | 1003 | z | 1003 | 8 | +--------+------+--------+-------+
若LEFT JOIN替換成RIGHT JOIN,則生成的表vt3如下:
+--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1001 | x | 1001 | 22 | | 1002 | y | 1002 | 30 | | 1003 | z | 1003 | 8 | | NULL | NULL | 1009 | 11 | +--------+------+--------+-------+
因為user_account(右表)里存在userid=1009這一行,而user_info(左表)里卻找不到這一行的記錄,所以會在第三步插入以下一行:
| NULL | NULL | 1009 | 11 |
上文引用的文章中提到了標準SQL定義的FULL JOIN,這在mysql里是不支持的,不過我們可以通過LEFT JOIN + UNION + RIGHT JOIN 來實現FULL JOIN:
SELECT * FROM user_info as i RIGHT JOIN user_account as a ON a.userid=i.userid union SELECT * FROM user_info as i LEFT JOIN user_account as a ON a.userid=i.userid;
他會返回如下結果:
+--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1001 | x | 1001 | 22 | | 1002 | y | 1002 | 30 | | 1003 | z | 1003 | 8 | | NULL | NULL | 1009 | 11 | | 1004 | a | NULL | NULL | | 1005 | b | NULL | NULL | | 1006 | c | NULL | NULL | | 1007 | d | NULL | NULL | | 1008 | e | NULL | NULL | +--------+------+--------+-------+
ps:其實我們從語義上就能看出LEFT JOIN和RIGHT JOIN沒什么差別,兩者的結果差異取決于左右表的放置順序,以下內容摘自mysql官方文檔:
RIGHT JOIN works analogously to LEFT JOIN. To keep code portable across databases, it is recommended that you use LEFT JOIN instead of RIGHT JOIN.
所以當你糾結使用LEFT JOIN還是RIGHT JOIN時,盡可能只使用LEFT JOIN吧
上文把JOIN的執行順序了解清楚之后,ON和WHERE的區別也就很好理解了。
舉例說明:
SELECT * FROM user_info as i LEFT JOIN user_account as a ON i.userid = a.userid and i.userid = 1003;
SELECT * FROM user_info as i LEFT JOIN user_account as a ON i.userid = a.userid where i.userid = 1003;
第一種情況LEFT JOIN在執行完第二步ON子句后,篩選出滿足i.userid = a.userid and i.userid = 1003的行,生成表vt2,然后執行第三步JOIN子句,將外部行添加進虛擬表生成vt3即最終結果:
vt2: +--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1003 | z | 1003 | 8 | +--------+------+--------+-------+ vt3: +--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1001 | x | NULL | NULL | | 1002 | y | NULL | NULL | | 1003 | z | 1003 | 8 | | 1004 | a | NULL | NULL | | 1005 | b | NULL | NULL | | 1006 | c | NULL | NULL | | 1007 | d | NULL | NULL | | 1008 | e | NULL | NULL | +--------+------+--------+-------+
而第二種情況LEFT JOIN在執行完第二步ON子句后,篩選出滿足i.userid = a.userid的行,生成表vt2;再執行第三步JOIN子句添加外部行生成表vt3;然后執行第四步WHERE子句,再對vt3表進行過濾生成vt4,得的最終結果:
vt2: +--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1001 | x | 1001 | 22 | | 1002 | y | 1002 | 30 | | 1003 | z | 1003 | 8 | +--------+------+--------+-------+ vt3: +--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1001 | x | 1001 | 22 | | 1002 | y | 1002 | 30 | | 1003 | z | 1003 | 8 | | 1004 | a | NULL | NULL | | 1005 | b | NULL | NULL | | 1006 | c | NULL | NULL | | 1007 | d | NULL | NULL | | 1008 | e | NULL | NULL | +--------+------+--------+-------+ vt4: +--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1003 | z | 1003 | 8 | +--------+------+--------+-------+
如果將上例的LEFT JOIN替換成INNER JOIN,不論將條件過濾放到ON還是WHERE里,結果都是一樣的,因為INNER JOIN不會執行第三步添加外部行
SELECT * FROM user_info as i INNER JOIN user_account as a ON i.userid = a.userid and i.userid = 1003;
SELECT * FROM user_info as i INNER JOIN user_account as a ON i.userid = a.userid where i.userid = 1003;
返回結果都是:
+--------+------+--------+-------+ | userid | name | userid | money | +--------+------+--------+-------+ | 1003 | z | 1003 | 8 | +--------+------+--------+-------+
感謝各位的閱讀!關于Mysq中JOIN有什么用就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。