保留左表所有行,右表無匹配則用 NULL 填充。
SELECT column_list
FROM left_table AS L
LEFT JOIN right_table AS R ON L.join_key = R.join_key;
左表 (L) 右表 (R) LEFT JOIN 結果 ┌─────────┐ ┌─────────┐ ┌─────────────────┐ │ A ●────┼───────┼─● B │ │ A B (匹配) │ │ C ●────┼───────┤ │ → │ C NULL (無匹配)│ │ D │ │ │ │ D NULL │ └─────────┘ └─────────┘ └─────────────────┘
-- 表 Persons (Id_P, LastName, FirstName)
-- 表 Orders (Id_O, OrderNo, Id_P)
SELECT p.LastName, p.FirstName, o.OrderNo
FROM Persons AS p
LEFT JOIN Orders AS o ON p.Id_P = o.Id_P
ORDER BY p.LastName;
LastName | FirstName | OrderNo
Adams | John | 22456
Adams | John | 24562
Carter | Thomas | 77895
Carter | Thomas | 44678
Bush | George | NULL -- 無訂單,但保留
| 連接類型 | 結果行數 | 用途 |
|---|---|---|
| INNER JOIN | 雙方都有匹配 | 核心業務關聯,雙方必須存在 |
| LEFT JOIN | 左表全保留 | 主表帶從表屬性,從表可選 |
| RIGHT JOIN | 右表全保留 | 少用,可改寫為 LEFT JOIN 交換表順序 |
SELECT u.name, o.order_no, oi.product_name, oi.qty
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
LEFT JOIN order_items oi ON o.id = oi.order_id
WHERE u.status = 'active';
每個 LEFT JOIN 都以前面結果集為左表,逐步擴展。
EXISTS 替代 LEFT JOIN ... WHERE R.id IS NOT NULL。-- 陷阱:右表條件寫在 WHERE 導致 LEFT JOIN 失效
SELECT * FROM a LEFT JOIN b ON a.id = b.a_id WHERE b.status = 'active';
-- 等價於 INNER JOIN,因 b.status=NULL 不滿足條件
-- 正確:右表條件移至 ON
SELECT * FROM a LEFT JOIN b ON a.id = b.a_id AND b.status = 'active';