oracle 9i起全面支持ansi sql:1999 join语法,执行性能与传统逗号语法等价,但可读性、可维护性及外连接表达能力更强;inner join必须显式写on条件,否则报ora-00905;on中列须带表前缀防ora-00918;where中勿重复连接条件,尤其外连接;left join中过滤条件位置错误(on vs where)会导致语义变化;full outer join可用但需注意版本与驱动兼容性,null不匹配;cross join和natural join风险高,应避免;显式on条件利于索引使用,隐式类型转换或函数会致全表扫描。

Oracle 从 9i 开始全面支持 ANSI SQL:1999 JOIN 语法,且与传统逗号语法在执行计划和性能上完全等价——但可读性、可维护性、外连接表达能力显著更强。
INNER JOIN 必须写 ON,不能省略条件
很多人误以为 JOIN 后不写 ON 也能运行,实际会报错:ORA-00905: missing keyword。ANSI 语法强制分离连接逻辑与过滤逻辑,ON 是必需子句。
-
ON中的列必须明确归属(如e.department_id = d.department_id),不能只写department_id = department_id - 若两表有同名列(如都含
id),不加别名或表前缀会导致ORA-00918: column ambiguously defined -
WHERE里不能再重复写连接条件——否则可能意外过滤掉本该保留的行(尤其在外连接中)
LEFT JOIN 的 NULL 填充行为取决于 ON 条件位置
这是最容易踩坑的地方:把本该放在 WHERE 的过滤条件错误塞进 ON,会导致左表“被悄悄过滤”。
- 正确写法(查所有员工 + 部门名,部门为空也保留):
SELECT e.name, d.department_name FROM employees e LEFT JOIN departments d ON e.dept_id = d.dept_id - 错误写法(看似加了部门筛选,实则让 LEFT 失效):
... LEFT JOIN departments d ON e.dept_id = d.dept_id AND d.status = 'ACTIVE'—— 这会让d.status != 'ACTIVE'的员工行依然保留,但d.department_name为 NULL;而如果把d.status = 'ACTIVE'放WHERE,就变成 INNER 效果,没部门或状态不符的员工直接被剔除
FULL OUTER JOIN 在 Oracle 中可用但需注意兼容性
Oracle 支持 FULL OUTER JOIN,但早期版本(如 8i)不支持,且某些旧应用层驱动(如部分 ODBC/JDBC 版本)可能解析失败。
- 替代方案更稳妥:
LEFT JOIN+RIGHT JOIN+UNION ALL(需手动去重并处理 NULL) -
FULL JOIN的ON条件仍受索引影响——若用函数包装(如ON UPPER(a.code) = UPPER(b.code)),很可能跳过索引 - 当连接字段允许 NULL 时,
FULL JOIN对 NULL 的匹配行为与=不同(NULL 不等于 NULL),结果可能比预期少
CROSS JOIN 和 NATURAL JOIN 尽量避免在生产环境使用
它们看起来简洁,但隐含风险极高。
-
CROSS JOIN没有ON,直接笛卡尔积——10 万 × 10 万 = 100 亿行,语句可能跑数小时甚至触发ORA-01555或内存溢出 -
NATURAL JOIN自动匹配所有同名列,一旦表结构新增同名字段(比如两个表都加了created_by),连接逻辑就突变,且无法通过执行计划快速察觉 - 显式写
INNER JOIN ... ON虽多敲几个字,但每次改表、加字段、调优时都少一分不确定性
真正麻烦的从来不是语法本身,而是 ON 条件里那些看不见的类型转换、函数包裹、NULL 处理逻辑——它们不会报错,但会让执行计划从走索引变成全表扫描,而且只在数据量上来时才暴露。











