SELECT * FROM a, b WHERE a.id = b.id;
-- 僅回傳雙方均有匹配的行
在 WHERE 條件的「缺邊」欄位加 (+),表示保留另一邊所有行。
| 類型 | 語法 | 結果 |
|---|---|---|
| 左外連接 | WHERE a.id = b.id(+) | 保留 A 所有行,B 無匹配則 NULL |
| 右外連接 | WHERE a.id(+) = b.id | 保留 B 所有行,A 無匹配則 NULL |
限制:不支援 FULL OUTER JOIN;(+) 不能用於 OR 條件、IN 子查詢、比較運算子兩側同時出現。
SELECT e.last_name, e.department_id, d.department_name
FROM employees e
LEFT OUTER JOIN departments d
ON (e.department_id = d.department_id);
-- 等價於 WHERE e.department_id = d.department_id(+)
-- 結果:所有員工 + 對應部門,無部門員工部門欄位為 NULL
SELECT e.last_name, e.department_id, d.department_name
FROM employees e
RIGHT OUTER JOIN departments d
ON (e.department_id = d.department_id);
-- 等價於 WHERE e.department_id(+) = d.department_id
-- 結果:所有部門 + 對應員工,無員工部門員工欄位為 NULL
SELECT e.last_name, e.department_id, d.department_name
FROM employees e
FULL OUTER JOIN departments d
ON (e.department_id = d.department_id);
-- 結果:所有員工 + 所有部門,雙邊無匹配皆保留,對方欄位為 NULL
-- 舊式 (+) 無法直接表達,需 UNION 兩邊外連接
SELECT e.last_name, d.department_name, l.city
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id
LEFT JOIN locations l ON d.location_id = l.location_id;
-- 依序保留 employees → departments → locations
若在 WHERE 條件中對外連接保留表的欄位加入非空過濾(d.department_name = 'Sales'),外連接將隱性轉為內連接。正確做法:將條件移至 ON 子句。
-- ❌ 錯誤:變成內連接
SELECT * FROM e LEFT JOIN d ON e.id = d.id WHERE d.name = 'Sales';
-- ✅ 正確:保留外連接語義
SELECT * FROM e LEFT JOIN d ON e.id = d.id AND d.name = 'Sales';
DBMS_STATS.GATHER_TABLE_STATS。| 需求 | ANSI 語法 | 舊式 (+) | 備註 |
|---|---|---|---|
| 保留左表 | LEFT JOIN | 右欄位 (+) | |
| 保留右表 | RIGHT JOIN | 左欄位 (+) | |
| 保留雙表 | FULL JOIN | 不支援 | 需 UNION |
| 多表鏈式 | 連續 LEFT/RIGHT JOIN | 極難維護 | ANSI 唯一選擇 |
外連接是多表關聯查詢的核心技能,掌握 ANSI 標準語法並理解語義邊界,是寫出正確、高效 SQL 的關鍵。