下文將使用兩個數據庫表 Table_A 和 Table_B 來進行示例講解,其結構與數據分別以下:php
mysql> SELECT * FROM Table_A ORDER BY PK ASC;
+----+---------+
| PK | Value |
+----+---------+
| 1 | both ab |
| 2 | only a |
+----+---------+
2 rows in set (0.00 sec)
mysql> SELECT * from Table_B ORDER BY PK ASC;
+----+---------+
| PK | Value |
+----+---------+
| 1 | both ab |
| 3 | only b |
+----+---------+
2 rows in set (0.00 sec)
其中 PK 爲 1 的記錄在 Table_A 和 Table_B 中都有,2 爲 Table_A 特有,3 爲 Table_B 特有。mysql
INNER JOIN 通常被譯做內鏈接。內鏈接查詢能將左表(表 A)和右表(表 B)中能關聯起來的數據鏈接後返回。sql
文氏圖:數據庫
示例查詢:ide
SELECT A.PK AS A_PK, B.PK AS B_PK, A.Value AS A_Value, B.Value AS B_Value FROM Table_A A INNER JOIN Table_B B ON A.PK = B.PK;
查詢結果:學習
+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
| 1 | 1 | both ab | both ab |
+------+------+---------+---------+
1 row in set (0.00 sec)
注:其中 A
爲 Table_A
的別名,B
爲 Table_B
的別名,下同。spa
LEFT JOIN 通常被譯做左鏈接,也寫做 LEFT OUTER JOIN。左鏈接查詢會返回左表(表 A)中全部記錄,無論右表(表 B)中有沒有關聯的數據。在右表中找到的關聯數據列也會被一塊兒返回。code
文氏圖:server
示例查詢:blog
SELECT A.PK AS A_PK, B.PK AS B_PK, A.Value AS A_Value, B.Value AS B_Value FROM Table_A A LEFT JOIN Table_B B ON A.PK = B.PK;
查詢結果:
+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
| 1 | 1 | both ab | both ba |
| 2 | NULL | only a | NULL |
+------+------+---------+---------+
2 rows in set (0.00 sec)
RIGHT JOIN 通常被譯做右鏈接,也寫做 RIGHT OUTER JOIN。右鏈接查詢會返回右表(表 B)中全部記錄,無論左表(表 A)中有沒有關聯的數據。在左表中找到的關聯數據列也會被一塊兒返回。
文氏圖:
示例查詢:
SELECT A.PK AS A_PK, B.PK AS B_PK, A.Value AS A_Value, B.Value AS B_Value FROM Table_A A RIGHT JOIN Table_B B ON A.PK = B.PK;
查詢結果:
+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
| 1 | 1 | both ab | both ba |
| NULL | 3 | NULL | only b |
+------+------+---------+---------+
2 rows in set (0.00 sec)
FULL OUTER JOIN 通常被譯做外鏈接、全鏈接,實際查詢語句中能夠寫做 FULL OUTER JOIN
或 FULL JOIN
。外鏈接查詢能返回左右表裏的全部記錄,其中左右表裏能關聯起來的記錄被鏈接後返回。
文氏圖:
示例查詢:
SELECT A.PK AS A_PK, B.PK AS B_PK, A.Value AS A_Value, B.Value AS B_Value FROM Table_A A FULL OUTER JOIN Table_B B ON A.PK = B.PK;
查詢結果:
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FULL OUTER JOIN Table_B B
ON A.PK = B.PK' at line 4
注:我當前示例使用的 MySQL 不支持 FULL OUTER JOIN
。
應當返回的結果(使用 UNION 模擬):
mysql> SELECT *
-> FROM Table_A
-> LEFT JOIN Table_B
-> ON Table_A.PK = Table_B.PK
-> UNION ALL
-> SELECT *
-> FROM Table_A
-> RIGHT JOIN Table_B
-> ON Table_A.PK = Table_B.PK
-> WHERE Table_A.PK IS NULL;
+------+---------+------+---------+
| PK | Value | PK | Value |
+------+---------+------+---------+
| 1 | both ab | 1 | both ba |
| 2 | only a | NULL | NULL |
| NULL | NULL | 3 | only b |
+------+---------+------+---------+
3 rows in set (0.00 sec)
以上四種,就是 SQL 裏常見 JOIN 的種類和概念了,看一下它們的合影:
有沒有感受少了些什麼,學數學集合時徹底不止這幾種狀況?確實如此,繼續看。
返回左表有但右表沒有關聯數據的記錄集。
文氏圖:
示例查詢:
SELECT A.PK AS A_PK, B.PK AS B_PK, A.Value AS A_Value, B.Value AS B_Value FROM Table_A A LEFT JOIN Table_B B ON A.PK = B.PK WHERE B.PK IS NULL;
查詢結果:
+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
| 2 | NULL | only a | NULL |
+------+------+---------+---------+
1 row in set (0.01 sec)
返回右表有但左表沒有關聯數據的記錄集。
文氏圖:
示例查詢:
SELECT A.PK AS A_PK, B.PK AS B_PK, A.Value AS A_Value, B.Value AS B_Value FROM Table_A A RIGHT JOIN Table_B B ON A.PK = B.PK WHERE A.PK IS NULL;
查詢結果:
+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
| NULL | 3 | NULL | only b |
+------+------+---------+---------+
1 row in set (0.00 sec)
返回左表和右表裏沒有相互關聯的記錄集。
文氏圖:
示例查詢:
SELECT A.PK AS A_PK, B.PK AS B_PK, A.Value AS A_Value, B.Value AS B_Value FROM Table_A A FULL OUTER JOIN Table_B B ON A.PK = B.PK WHERE A.PK IS NULL OR B.PK IS NULL;
由於使用到了 FULL OUTER JOIN,MySQL 在執行該查詢時再次報錯。
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FULL OUTER JOIN Table_B B
ON A.PK = B.PK
WHERE A.PK IS NULL
OR B.PK IS NULL' at line 4
應當返回的結果(用 UNION 模擬):
mysql> SELECT *
-> FROM Table_A
-> LEFT JOIN Table_B
-> ON Table_A.PK = Table_B.PK
-> WHERE Table_B.PK IS NULL
-> UNION ALL
-> SELECT *
-> FROM Table_A
-> RIGHT JOIN Table_B
-> ON Table_A.PK = Table_B.PK
-> WHERE Table_A.PK IS NULL;
+------+--------+------+--------+
| PK | Value | PK | Value |
+------+--------+------+--------+
| 2 | only a | NULL | NULL |
| NULL | NULL | 3 | only b |
+------+--------+------+--------+
2 rows in set (0.00 sec)
以上七種用法基本上能夠覆蓋各類 JOIN 查詢了。七種用法的全家福:
看着它們,我彷彿回到了當年學數學,求交集並集的時代……
順帶張貼一下 C.L. Moffatt 帶 SQL 語句的圖片,配合學習,風味更佳:
除以上幾種外,還有更多的 JOIN 用法,好比 CROSS JOIN(迪卡爾集)、SELF JOIN,能夠參考 SQL JOINS Slide Presentation 學習。
返回左表與右表之間符合條件的記錄的迪卡爾集。
圖示:
示例查詢:
SELECT A.PK AS A_PK, B.PK AS B_PK, A.Value AS A_Value, B.Value AS B_Value FROM Table_A A CROSS JOIN Table_B B;
查詢結果:
+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
| 1 | 1 | both ab | both ba |
| 2 | 1 | only a | both ba |
| 1 | 3 | both ab | only b |
| 2 | 3 | only a | only b |
+------+------+---------+---------+
4 rows in set (0.00 sec)
上面講過的幾種 JOIN 查詢的結果均可以用 CROSS JOIN 加條件模擬出來,好比 INNER JOIN 對應 CROSS JOIN ... WHERE A.PK = B.PK
。
返回表與本身鏈接後符合條件的記錄,通常用在表裏有一個字段是用主鍵做爲外鍵的狀況。
好比 Table_C 的結構與數據以下:
+--------+----------+-------------+
| EMP_ID | EMP_NAME | EMP_SUPV_ID |
+--------+----------+-------------+
| 1001 | Ma | NULL |
| 1002 | Zhuang | 1001 |
+--------+----------+-------------+
2 rows in set (0.00 sec)
EMP_ID 字段表示員工 ID,EMP_NAME 字段表示員工姓名,EMP_SUPV_ID 表示主管 ID。
示例查詢:
如今咱們想查詢全部有主管的員工及其對應的主管 ID 和姓名,就能夠用 SELF JOIN 來實現。
SELECT A.EMP_ID AS EMP_ID, A.EMP_NAME AS EMP_NAME, B.EMP_ID AS EMP_SUPV_ID, B.EMP_NAME AS EMP_SUPV_NAME FROM Table_C A, Table_C B WHERE A.EMP_SUPV_ID = B.EMP_ID;
查詢結果:
+--------+----------+-------------+---------------+
| EMP_ID | EMP_NAME | EMP_SUPV_ID | EMP_SUPV_NAME |
+--------+----------+-------------+---------------+
| 1002 | Zhuang | 1001 | Ma |
+--------+----------+-------------+---------------+
1 row in set (0.00 sec)
文中的圖使用 Keynote 繪製;
我的的體會是 SQL 裏的 JOIN 查詢與數學裏的求交集、並集等很像;
SQLite 不支持 RIGHT JOIN 和 FULL OUTER JOIN,可使用 LEFT JOIN 和 UNION 來達到相同的效果;
MySQL 不支持 FULL OUTER JOIN,可使用 LEFT JOIN 和 UNION 來達到相同的效果;