22 SQL Join2
1. 前言
上一小節中介紹了連線操作中內連線,本小節,我們將學習外連線
。
外連線有些許不同,它並不要求兩張表中的記錄都能夠匹配,即使沒有匹配到也會保留資料,被保留全部資料的表被稱為保留表。
外連線可以根據保留表來進一步分為:左外連線
(左邊的表資料會被保留),右外連線
(右邊的表資料會被保留)和全連線
(兩邊的表均被保留)。
外連線沒有隱式的連線方式,必須通過 Join 與 On 顯式的指定連線方式和連線條件。
本小節測試資料如下,請先在資料庫中執行:
DROP TABLE IF EXISTS imooc_class;
CREATE TABLE imooc_class
(
id int PRIMARY KEY,
class_name varchar(20)
);
INSERT INTO imooc_class(id,class_name) VALUES(1,'SQL必知必會'), (2,'C語言入門'),
(3,'JAVA高效程式設計'),(4,'JVM花落知多少');
DROP TABLE IF EXISTS imooc_user;
CREATE TABLE imooc_user
(
id int PRIMARY KEY,
username varchar(20),
class_id int references imooc_class(id)
);
INSERT INTO imooc_user(id,username,class_id) VALUES(1,'pedro', 1), (2,'peter', 1),
(3,'faker', 2), (4,'lucy', 4),(5,'jery', NULL);
說明: 我們分別新建了 imooc_class 表——課程表,和 imooc_user 表——使用者表;其中 imooc_user 表中的 class_id 作為外來鍵指向 imooc_class 的主鍵id;若 class_id 為 NULL 則表示該使用者暫時還未加入任何課程,否則 class_id 表示使用者參加課程的 id 。
2. 左外連線
左外連線(Left Outer Join),簡稱左連線(Left Join);若 A 和 B 兩表進行左外連線,會在結果中包含左表(即表 A)的所有記錄,即使那些記錄在右表B 沒有符合連線條件相應的匹配記錄,未匹配的記錄會給予 NULL 填充。
維恩圖表示如下:
2.1 例1 左連線查詢
請書寫 SQL 語句,查詢imooc_user
表中每一個使用者姓名和該使用者所參加課程的名稱。
分析:
由題幹可知,查詢的結果應是使用者姓名以及參加課程,因此 imooc_user 表應該作為保留表;考慮到使用左連線,所以 imooc_user 表是左表,imooc_class 表作為右表。
語句:
整理可得語句如下:
SELECT username,class_name FROM imooc_user LEFT OUTER JOIN imooc_class ON imooc_user.class_id = imooc_class.id;
結果如下:
+----------+---------------+
| username | class_name |
+----------+---------------+
| pedro | SQL必知必會 |
| peter | SQL必知必會 |
| faker | C語言入門 |
| lucy | JVM花落知多少 |
| jery | <null> |
+----------+---------------+
3. 右外連線
右外連線(Right Outer Join),簡稱右連線(Right Join);若 A 和 B 兩表進行右外連線,會在結果中包含右表(即表 B)的所有記錄,即使那些記錄在左表 A 中沒有符合連線條件相應的匹配記錄,未匹配的記錄會給予 NULL 填充。
維恩圖表示如下:
3.1 例2 右連線
請書寫SQL語句,查詢imooc_user
表中每一門課程和該課程下參與的使用者。
分析:
由題幹可知,imooc_class 應作為保留表,考慮到使用右連線,因此 imooc_class 是右表;連線條件是外來鍵 class_id。
語句:
整理可得語句如下:
SELECT class_name,username FROM imooc_user RIGHT OUTER JOIN imooc_class ON imooc_class.id = imooc_user.class_id;
結果如下:
+---------------+----------+
| class_name | username |
+---------------+----------+
| SQL必知必會 | pedro |
| SQL必知必會 | peter |
| C語言入門 | faker |
| JVM花落知多少 | lucy |
| JAVA高效程式設計 | <null> |
+---------------+----------+
提示:SQLite 是不支援右連線的,卻可以通過更換保留表的位置用左連線來模擬右連線。
4. 全連線
全連線是左、右外連線的並集。查詢結果會包含被連線表的所有記錄,若缺少匹配的記錄,將以 NULL 填充。
維恩圖表示如下:
4.1 例3 全連線
請書寫 SQL 語句,返回imooc_class
和imooc_user
表的全連線。
SELECT * FROM imooc_class FULL OUTER JOIN imooc_user ON imooc_class.id = imooc_user.class_id;
查詢結果如下:
+--------+----------+----------+--------+---------------+
| id | username | class_id | id | class_name |
+--------+----------+----------+--------+---------------+
| 1 | pedro | 1 | 1 | SQL必知必會 |
| 2 | peter | 1 | 1 | SQL必知必會 |
| 3 | faker | 2 | 2 | C語言入門 |
| 4 | lucy | 4 | 4 | JVM花落知多少 |
| 5 | jery | <null> | <null> | <null> |
| <null> | <null> | <null> | 3 | JAVA高效程式設計 |
+--------+----------+----------+--------+---------------+
一些資料庫,比如 MySQL 是不支援全連線的,但可以通過左、右外連線的並集(Union)來模擬實現,如下:
SELECT *
FROM imooc_user
LEFT JOIN imooc_class
ON imooc_class.id = imooc_user.class_id
UNION
SELECT *
FROM imooc_user
RIGHT JOIN imooc_class
ON imooc_class.id = imooc_user.class_id
WHERE imooc_user.class_id IS NULL;
提示: SQLite 不支援右連線和全連線,也可以通過左連線來模擬右連線,從而實現全連線。
5. 個人經驗
- 外連線是連線操作的
重點
,請多多聯絡並熟練掌握。 - 左、右連線可以通過更換表的位置來實現同等作用,因此一些資料庫只支援左連線。
- 全連線的使用較少,所以有些資料庫會不支援,但是使用左、右連線也可以達到相同效果。