多表查詢是 SQL 核心技能之一。Oracle 同時支援傳統「(+)」語法與 ANSI SQL:1999 標準語法,理解兩者差異與適用場景,能寫出更易維護、效能更穩定的查詢。
SELECT e.ename, e.job, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno AND e.sal > 2000;
SELECT e.ename, e.job, e.sal, d.dname FROM emp e INNER JOIN dept d ON e.deptno = d.deptno WHERE e.sal > 2000;
INNER 關鍵字可省略,單寫 JOIN 即視為內連接。標準語法將「連接條件」與「過濾條件」分離,可讀性更佳。
外連接分為左外連接、右外連接、全外連接。Oracle 傳統語法使用 (+) 標示「虛擬補齊」的一方。
情境:查詢所有部門及其員工,即便部門無員工也要列出。
-- 傳統語法:(+) 放在右表欄位 SELECT e.ename, e.job, e.sal, d.dname FROM emp e, dept d WHERE e.deptno(+) = d.deptno; -- ANSI 語法 SELECT e.ename, e.job, e.sal, d.dname FROM emp e RIGHT OUTER JOIN dept d ON e.deptno = d.deptno;
注意:傳統語法中 (+) 出現在 右邊 代表左外連接 (保留右表);ANSI 則用 RIGHT JOIN 明確語意。
-- 傳統語法:(+) 放在左表欄位 SELECT e.ename, e.job, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno(+); -- ANSI 語法 SELECT e.ename, e.job, e.sal, d.dname FROM emp e LEFT OUTER JOIN dept d ON e.deptno = d.deptno;
傳統語法不支援直接在同一 WHERE 子句兩側同時加 (+),需改用 UNION 組合:
SELECT e.ename, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno(+) UNION SELECT e.ename, d.dname FROM emp e, dept d WHERE e.deptno(+) = d.deptno;
ANSI 標準語法簡潔得多:
SELECT e.ename, d.dname FROM emp e FULL OUTER JOIN dept d ON e.deptno = d.deptno;
| 項目 | 傳統 (+) 語法 | ANSI JOIN 語法 |
|---|---|---|
| 可讀性 | 連接/過濾條件混雜在 WHERE | ON 子句隔離連接條件 |
| 全外連接 | 需 UNION 組合,效能較差 | 原生支援 FULL OUTER JOIN |
| 多表連接順序 | 靠 WHERE 條件順序暗示 | JOIN 順序即執行順序,直觀 |
| 相容性 | Oracle 專屬 | 跨資料庫通用 |
| 除錯便利性 | 難以單獨測試單一 JOIN | 可逐步加入 JOIN 驗證 |
(+) 導致隱性內連接)。WHERE 過濾右表非空欄位 (如 d.loc = 'TAIPEI'),會隱性轉為內連接;請將條件移至 ON 子句:LEFT JOIN dept d ON e.deptno = d.deptno AND d.loc = 'TAIPEI'/*+ LEADING */ / USE_HASH Hint 引導最佳化器。-- 內連接 JOIN / INNER JOIN -- 左外連接 (保留左表) LEFT [OUTER] JOIN -- 右外連接 (保留右表) RIGHT [OUTER] JOIN -- 全外連接 FULL [OUTER] JOIN -- 交叉連接 (笛卡兒積) CROSS JOIN
建議新專案統一採用 ANSI JOIN 語法,既符合標準、又利團隊協作與跨平台移植;僅在維護舊版 Oracle (8i/9i) 既有程式碼時才需閱讀 (+) 語法。