JOIN 是多表查詢的核心,掌握各類 JOIN 的語義與結果集差異,能寫出正確且高效的 SQL。本文用文字「圖解」五大 JOIN 類型,並附帶避坑指南。
| JOIN 類型 | 別名 | 結果集定義 | 關鍵字 |
|---|---|---|---|
| LEFT JOIN | LEFT OUTER JOIN | 以左表為基準,返回左表所有行;右表匹配不到則填 NULL | 左表全保 |
| RIGHT JOIN | RIGHT OUTER JOIN | 以右表為基準,返回右表所有行;左表匹配不到則填 NULL | 右表全保 |
| INNER JOIN | JOIN | 僅返回兩表條件匹配的行(交集) | 內連接 |
| CROSS JOIN | 無 | 笛卡爾積:左表每行 × 右表每行,無 ON 條件 | 笛卡爾積 |
| FULL OUTER JOIN | FULL JOIN | 左右表所有行並集;無匹配側填 NULL(MySQL 不直接支援,需 UNION 模擬) | 全外連接 |
-- 範例表
CREATE TABLE `dept` (id INT PRIMARY KEY, name VARCHAR(20));
CREATE TABLE `emp` (id INT PRIMARY KEY, name VARCHAR(20), dept_id INT);
INSERT INTO dept VALUES (1,'研發'),(2,'市場'),(3,'運營');
INSERT INTO emp VALUES (101,'Alice',1),(102,'Bob',1),(103,'Cathy',2),(104,'David',NULL);
SELECT e.name, d.name AS dept
FROM emp e
INNER JOIN dept d ON e.dept_id = d.id;
-- 結果:Alice-研發, Bob-研發, Cathy-市場 (David 無 dept_id 被過濾)
SELECT e.name, d.name AS dept
FROM emp e
LEFT JOIN dept d ON e.dept_id = d.id;
-- 結果:Alice-研發, Bob-研發, Cathy-市場, David-NULL
SELECT e.name, d.name AS dept
FROM emp e
RIGHT JOIN dept d ON e.dept_id = d.id;
-- 結果:Alice-研發, Bob-研發, Cathy-市場, NULL-運營
SELECT e.name, d.name
FROM emp e
CROSS JOIN dept d;
-- 結果:4 員工 × 3 部門 = 12 行
SELECT e.name, d.name
FROM emp e
LEFT JOIN dept d ON e.dept_id = d.id
UNION
SELECT e.name, d.name
FROM emp e
RIGHT JOIN dept d ON e.dept_id = d.id;
-- 結果:左右表所有行並集,無匹配處為 NULL
RIGHT JOIN 或調換表順序。LEFT JOIN ... ON a.id=b.id AND b.status=1 保留左表所有行;LEFT JOIN ... ON a.id=b.id WHERE b.status=1 會隱性轉為 INNER JOIN。INNER JOIN : (A ∩ B) LEFT JOIN : (A ∩ B) ∪ (A - B) -- A 全部 RIGHT JOIN : (A ∩ B) ∪ (B - A) -- B 全部 FULL OUTER JOIN: (A ∪ B) -- 全部 CROSS JOIN : A × B -- 笛卡爾積
熟練掌握 JOIN 語義,是寫出正確、高效多表查詢的基石。