JOIN的含義就如英文單詞「join」同樣,鏈接兩張表,大體分爲內鏈接,外鏈接,右鏈接,左鏈接,天然鏈接。這裏描述先甩出一張用爛了的圖,而後插入測試數據。測試
測試數據表:優化
CREATE TABLE t_blog( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(50), typeId INT ); INSERT INTO t_blog VALUES(NULL,'aaa',1), (NULL,'bbb',2),(NULL,'ccc',3),(NULL,'ddd',4),(NULL,'eee',4), (NULL,'fff',3),(NULL,'ggg',2),(NULL,'hhh',NULL),(NULL,'iii',NULL),(NULL,'jjj',NULL); CREATE TABLE t_type( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) ); INSERT INTO t_type VALUES (NULL,'C++'), (NULL,'C'),(NULL,'JAVA'),(NULL,'C#'),(NULL,'JVASCRIPT');
SELECT * FROM t_blog; +----+-------+--------+ | id | title | typeId | +----+-------+--------+ | 1 | aaa | 1 | | 2 | bbb | 2 | | 3 | ccc | 3 | | 4 | ddd | 4 | | 5 | eee | 4 | | 6 | fff | 3 | | 7 | ggg | 2 | | 8 | hhh | NULL | | 9 | iii | NULL | | 10 | jjj | NULL | +----+-------+--------+
SELECT * FROM t_type; +----+------------+ | id | name | +----+------------+ | 1 | C++ | | 2 | C | | 3 | Java | | 4 | C# | | 5 | Javascript | +----+------------+
要理解各類JOIN首先要理解笛卡爾積。笛卡爾積就是將A表的每一條記錄與B表的每一條記錄強行拼在一塊兒。因此,若是A表有n條記錄,B表有m條記錄,笛卡爾積產生的結果就會產生n*m條記錄。下面的例子,t_blog有10條記錄,t_type有5條記錄,全部他們倆的笛卡爾積有50條記錄。有五種產生笛卡爾積的方式以下。spa
SELECT * FROM t_blog CROSS JOIN t_type; SELECT * FROM t_blog INNER JOIN t_type; SELECT * FROM t_blog,t_type; SELECT * FROM t_blog NATURE JOIN t_type;
+----+-------+--------+----+------------+ | id | title | typeId | id | name | +----+-------+--------+----+------------+ | 1 | aaa | 1 | 1 | C++ | | 1 | aaa | 1 | 2 | C | | 1 | aaa | 1 | 3 | Java | | 1 | aaa | 1 | 4 | C# | | 1 | aaa | 1 | 5 | Javascript | | 2 | bbb | 2 | 1 | C++ | | 2 | bbb | 2 | 2 | C | | 2 | bbb | 2 | 3 | Java | | 2 | bbb | 2 | 4 | C# | | 2 | bbb | 2 | 5 | Javascript | | 3 | ccc | 3 | 1 | C++ | | 3 | ccc | 3 | 2 | C | | 3 | ccc | 3 | 3 | Java | | 3 | ccc | 3 | 4 | C# | | 3 | ccc | 3 | 5 | Javascript | | 4 | ddd | 4 | 1 | C++ | | 4 | ddd | 4 | 2 | C | | 4 | ddd | 4 | 3 | Java | | 4 | ddd | 4 | 4 | C# | | 4 | ddd | 4 | 5 | Javascript | | 5 | eee | 4 | 1 | C++ | | 5 | eee | 4 | 2 | C | | 5 | eee | 4 | 3 | Java | | 5 | eee | 4 | 4 | C# | | 5 | eee | 4 | 5 | Javascript | | 6 | fff | 3 | 1 | C++ | | 6 | fff | 3 | 2 | C | | 6 | fff | 3 | 3 | Java | | 6 | fff | 3 | 4 | C# | | 6 | fff | 3 | 5 | Javascript | | 7 | ggg | 2 | 1 | C++ | | 7 | ggg | 2 | 2 | C | | 7 | ggg | 2 | 3 | Java | | 7 | ggg | 2 | 4 | C# | | 7 | ggg | 2 | 5 | Javascript | | 8 | hhh | NULL | 1 | C++ | | 8 | hhh | NULL | 2 | C | | 8 | hhh | NULL | 3 | Java | | 8 | hhh | NULL | 4 | C# | | 8 | hhh | NULL | 5 | Javascript | | 9 | iii | NULL | 1 | C++ | | 9 | iii | NULL | 2 | C | | 9 | iii | NULL | 3 | Java | | 9 | iii | NULL | 4 | C# | | 9 | iii | NULL | 5 | Javascript | | 10 | jjj | NULL | 1 | C++ | | 10 | jjj | NULL | 2 | C | | 10 | jjj | NULL | 3 | Java | | 10 | jjj | NULL | 4 | C# | | 10 | jjj | NULL | 5 | Javascript | +----+-------+--------+----+------------+
內鏈接INNER JOIN是最經常使用的鏈接操做。從數學的角度講就是求兩個表的交集,從笛卡爾積的角度講就是從笛卡爾積中挑出ON子句條件成立的記錄。有INNER JOIN,WHERE(等值鏈接),STRAIGHT_JOIN,JOIN(省略INNER)四種寫法。至於哪一種好我會在MySQL的JOIN(二):優化講述。示例以下。設計
SELECT * FROM t_blog INNER JOIN t_type ON t_blog.typeId=t_type.id; SELECT * FROM t_blog,t_type WHERE t_blog.typeId=t_type.id; SELECT * FROM t_blog STRAIGHT_JOIN t_type ON t_blog.typeId=t_type.id; --注意STRIGHT_JOIN有個下劃線 SELECT * FROM t_blog JOIN t_type ON t_blog.typeId=t_type.id; +----+-------+--------+----+------+ | id | title | typeId | id | name | +----+-------+--------+----+------+ | 1 | aaa | 1 | 1 | C++ | | 2 | bbb | 2 | 2 | C | | 7 | ggg | 2 | 2 | C | | 3 | ccc | 3 | 3 | Java | | 6 | fff | 3 | 3 | Java | | 4 | ddd | 4 | 4 | C# | | 5 | eee | 4 | 4 | C# | +----+-------+--------+----+------+
左鏈接LEFT JOIN的含義就是求兩個表的交集外加左表剩下的數據。依舊從笛卡爾積的角度講,就是先從笛卡爾積中挑出ON子句條件成立的記錄,而後加上左表中剩餘的記錄(見最後三條)。code
SELECT * FROM t_blog LEFT JOIN t_type ON t_blog.typeId=t_type.id; +----+-------+--------+------+------+ | id | title | typeId | id | name | +----+-------+--------+------+------+ | 1 | aaa | 1 | 1 | C++ | | 2 | bbb | 2 | 2 | C | | 7 | ggg | 2 | 2 | C | | 3 | ccc | 3 | 3 | Java | | 6 | fff | 3 | 3 | Java | | 4 | ddd | 4 | 4 | C# | | 5 | eee | 4 | 4 | C# | | 8 | hhh | NULL | NULL | NULL | | 9 | iii | NULL | NULL | NULL | | 10 | jjj | NULL | NULL | NULL | +----+-------+--------+------+------+
同理右鏈接RIGHT JOIN就是求兩個表的交集外加右表剩下的數據。再次從笛卡爾積的角度描述,右鏈接就是從笛卡爾積中挑出ON子句條件成立的記錄,而後加上右表中剩餘的記錄(見最後一條)。blog
SELECT * FROM t_blog RIGHT JOIN t_type ON t_blog.typeId=t_type.id; +------+-------+--------+----+------------+ | id | title | typeId | id | name | +------+-------+--------+----+------------+ | 1 | aaa | 1 | 1 | C++ | | 2 | bbb | 2 | 2 | C | | 3 | ccc | 3 | 3 | Java | | 4 | ddd | 4 | 4 | C# | | 5 | eee | 4 | 4 | C# | | 6 | fff | 3 | 3 | Java | | 7 | ggg | 2 | 2 | C | | NULL | NULL | NULL | 5 | Javascript | +------+-------+--------+----+------------+
外鏈接就是求兩個集合的並集。從笛卡爾積的角度講就是從笛卡爾積中挑出ON子句條件成立的記錄,而後加上左表中剩餘的記錄,最後加上右表中剩餘的記錄。另外MySQL不支持OUTER JOIN,可是咱們能夠對左鏈接和右鏈接的結果作UNION操做來實現。ip
SELECT * FROM t_blog LEFT JOIN t_type ON t_blog.typeId=t_type.id UNION SELECT * FROM t_blog RIGHT JOIN t_type ON t_blog.typeId=t_type.id; +------+-------+--------+------+------------+ | id | title | typeId | id | name | +------+-------+--------+------+------------+ | 1 | aaa | 1 | 1 | C++ | | 2 | bbb | 2 | 2 | C | | 7 | ggg | 2 | 2 | C | | 3 | ccc | 3 | 3 | Java | | 6 | fff | 3 | 3 | Java | | 4 | ddd | 4 | 4 | C# | | 5 | eee | 4 | 4 | C# | | 8 | hhh | NULL | NULL | NULL | | 9 | iii | NULL | NULL | NULL | | 10 | jjj | NULL | NULL | NULL | | NULL | NULL | NULL | 5 | Javascript | +------+-------+--------+------+------------+
MySQL中鏈接SQL語句中,ON子句的語法格式爲:table1.column_name = table2.column_name。當模式設計對聯接表的列採用了相同的命名樣式時,就可使用 USING 語法來簡化 ON 語法,格式爲:USING(column_name)。
因此,USING的功能至關於ON,區別在於USING指定一個屬性名用於鏈接兩個表,而ON指定一個條件。另外,SELECT *時,USING會去除USING指定的列,而ON不會。實例以下。博客
SELECT * FROM t_blog INNER JOIN t_type ON t_blog.typeId =t_type.id; +----+-------+--------+----+------+ | id | title | typeId | id | name | +----+-------+--------+----+------+ | 1 | aaa | 1 | 1 | C++ | | 2 | bbb | 2 | 2 | C | | 7 | ggg | 2 | 2 | C | | 3 | ccc | 3 | 3 | Java | | 6 | fff | 3 | 3 | Java | | 4 | ddd | 4 | 4 | C# | | 5 | eee | 4 | 4 | C# | +----+-------+--------+----+------+ SELECT * FROM t_blog INNER JOIN t_type USING(typeId); ERROR 1054 (42S22): Unknown column 'typeId' in 'from clause' -- 這裏t_blog的typeId與t_type的id不一樣名,沒法用Using,這裏用id代替下。 SELECT * FROM t_blog INNER JOIN t_type ON t_blog.id = t_type.id; +----+-------+--------+----+-----------+ | id | title | typeId | id | name | +----+-------+--------+----+-----------+ | 1 | aaa | 1 | 1 | C++ | | 2 | bbb | 2 | 2 | C | | 3 | ccc | 3 | 3 | JAVA | | 4 | ddd | 4 | 4 | C# | | 5 | eee | 4 | 5 | JVASCRIPT | +----+-------+--------+----+-----------+ SELECT * FROM t_blog INNER JOIN t_type USING(id); +----+-------+--------+------------+ | id | title | typeId | name | +----+-------+--------+------------+ | 1 | aaa | 1 | C++ | | 2 | bbb | 2 | C | | 3 | ccc | 3 | Java | | 4 | ddd | 4 | C# | | 5 | eee | 4 | Javascript | +----+-------+--------+------------+
天然鏈接就是USING子句的簡化版,它找出兩個表中相同的列做爲鏈接條件進行鏈接。有左天然鏈接,右天然鏈接和普通天然鏈接之分。在t_blog和t_type示例中,兩個表相同的列是id,因此會拿id做爲鏈接條件。
另外千萬分清下面三條語句的區別 。
天然鏈接:SELECT * FROM t_blog NATURAL JOIN t_type; //NATURAL 爲關鍵字,表示天然鏈接
笛卡爾積:SELECT * FROM t_blog NATURA JOIN t_type; //NATURA 爲表的別名
笛卡爾積:SELECT * FROM t_blog NATURE JOIN t_type;//NATURE 爲表的別名數學
SELECT * FROM t_blog NATURAL JOIN t_type; SELECT t_blog.id,title,typeId,t_type.name FROM t_blog,t_type WHERE t_blog.id=t_type.id; SELECT t_blog.id,title,typeId,t_type.name FROM t_blog INNER JOIN t_type ON t_blog.id=t_type.id; SELECT t_blog.id,title,typeId,t_type.name FROM t_blog INNER JOIN t_type USING(id); +----+-------+--------+------------+ | id | title | typeId | name | +----+-------+--------+------------+ | 1 | aaa | 1 | C++ | | 2 | bbb | 2 | C | | 3 | ccc | 3 | Java | | 4 | ddd | 4 | C# | | 5 | eee | 4 | Javascript | +----+-------+--------+------------+ SELECT * FROM t_blog NATURAL LEFT JOIN t_type; SELECT t_blog.id,title,typeId,t_type.name FROM t_blog LEFT JOIN t_type ON t_blog.id=t_type.id; SELECT t_blog.id,title,typeId,t_type.name FROM t_blog LEFT JOIN t_type USING(id); +----+-------+--------+------------+ | id | title | typeId | name | +----+-------+--------+------------+ | 1 | aaa | 1 | C++ | | 2 | bbb | 2 | C | | 3 | ccc | 3 | Java | | 4 | ddd | 4 | C# | | 5 | eee | 4 | Javascript | | 6 | fff | 3 | NULL | | 7 | ggg | 2 | NULL | | 8 | hhh | NULL | NULL | | 9 | iii | NULL | NULL | | 10 | jjj | NULL | NULL | +----+-------+--------+------------+ SELECT * FROM t_blog NATURAL RIGHT JOIN t_type; SELECT t_blog.id,title,typeId,t_type.name FROM t_blog RIGHT JOIN t_type ON t_blog.id=t_type.id; SELECT t_blog.id,title,typeId,t_type.name FROM t_blog RIGHT JOIN t_type USING(id); +----+------------+-------+--------+ | id | name | title | typeId | +----+------------+-------+--------+ | 1 | C++ | aaa | 1 | | 2 | C | bbb | 2 | | 3 | Java | ccc | 3 | | 4 | C# | ddd | 4 | | 5 | Javascript | eee | 4 | +----+------------+-------+--------+
博客開頭給出的第一張圖除去講了的內鏈接、左鏈接、右鏈接、外鏈接,還有一些特殊的韋恩圖,這裏補充一下。it
SELECT * FROM t_blog LEFT JOIN t_type ON t_blog.typeId=t_type.id WHERE t_type.id IS NULL; +----+-------+--------+------+------+ | id | title | typeId | id | name | +----+-------+--------+------+------+ | 8 | hhh | NULL | NULL | NULL | | 9 | iii | NULL | NULL | NULL | | 10 | jjj | NULL | NULL | NULL | +----+-------+--------+------+------+ SELECT * FROM t_blog RIGHT JOIN t_type ON t_blog.typeId=t_type.id WHERE t_blog.id IS NULL; +------+-------+--------+----+------------+ | id | title | typeId | id | name | +------+-------+--------+----+------------+ | NULL | NULL | NULL | 5 | Javascript | +------+-------+--------+----+------------+ SELECT * FROM t_blog LEFT JOIN t_type ON t_blog.typeId=t_type.id WHERE t_type.id IS NULL UNION SELECT * FROM t_blog RIGHT JOIN t_type ON t_blog.typeId=t_type.id WHERE t_blog.id IS NULL; +------+-------+--------+------+------------+ | id | title | typeId | id | name | +------+-------+--------+------+------------+ | 8 | hhh | NULL | NULL | NULL | | 9 | iii | NULL | NULL | NULL | | 10 | jjj | NULL | NULL | NULL | | NULL | NULL | NULL | 5 | Javascript | +------+-------+--------+------+------------+
這篇博客發現有點「孔乙己:茴字的四種寫法的感受」,但仍是有收穫的。