Oracle早期的外连接写法是在连接条件上追加一个加号(+),例如dept.deptno = emp.deptno(+),表示以dept表为主表做左外连接。这种语法诞生于SQL标准尚未普及的年代,虽然Oracle至今仍兼容它,但官方文档已明确建议改用ANSI标准的JOIN关键字。新接手项目的开发者看到满屏的(+)往往一头雾水,理解错了方向还会查出错误结果,因此把旧语法重构成标准JOIN写法非常有必要。

先弄懂(+)符号的确切含义
(+)的核心规则只有一句话:加号写在哪个表的列后面,哪个表就是“被补充NULL的表”,也就是外连接中的从表。举例来说,a.id = b.id(+)表示a表数据全部保留,b表中没有匹配行的位置用NULL填充,等价于a LEFT JOIN b。反过来,如果写成a.id(+) = b.id,则以b表为主,等价于a RIGHT JOIN b。
这个规则看似简单,实际阅读老代码时最容易搞反方向。一个记忆技巧是:加号代表“缺数据的那个表”,也就是可能被NULL补齐的一侧。看下面这条典型的旧式查询:
-- 旧语法:以 d 为主表,e 为从表 SELECT d.dname, e.ename FROM dept d, emp e WHERE d.deptno = e.deptno(+) AND e.job(+) = 'CLERK';
注意这里有个隐蔽的坑:e.job(+) = 'CLERK'这个过滤条件也带了加号。在旧语法中,从表的过滤条件如果不加(+),会被放到WHERE里当成连接后过滤,导致左外连接退化为内连接。带(+)的写法等价于ANSI语法里把条件放到ON子句中。这是迁移时最容易出错的地方,务必逐条检查WHERE中的每个条件。
新旧语法对照与重构方法
标准的转换对应关系是:(+)写在右表列上转为LEFT JOIN,写在左表列上转为RIGHT JOIN,两张表都带(+)则转为FULL JOIN。重构时先把FROM里的逗号分隔改成JOIN关键字,再把连接条件从WHERE搬到ON子句,最后仔细区分哪些过滤条件应该留在WHERE、哪些应该进ON。
上一节的例子改写后如下:
-- ANSI 标准语法 SELECT d.dname, e.ename FROM dept d LEFT JOIN emp e ON d.deptno = e.deptno AND e.job = 'CLERK';
如果希望只对job为CLERK的员工做过滤、但保留所有部门(哪怕没有CLERK),条件放ON里没错;如果想在连接完成后再过滤掉某些部门,条件就应该写在WHERE里。ON和WHERE的语义差异在外连接中至关重要,旧语法靠加号来区分,新语法则靠位置区分,后者意图明显更清晰。
再看一个双表都有(+)的例子,它对应全外连接:
-- 旧语法:全外连接 SELECT a.id, b.id FROM t1 a, t2 b WHERE a.id(+) = b.id(+); -- ANSI 等价写法 SELECT a.id, b.id FROM t1 a FULL JOIN t2 b ON a.id = b.id;
顺便一提,旧语法还有个硬伤:无法直接表达两表都带(+)的写法在某些版本会直接报错,只能借助UNION ALL拼凑,而ANSI的FULL JOIN天然支持。这也是Oracle官方推动标准语法的原因之一。此外,旧语法中一个表如果同时与多个表做外连接,(+)的排列组合极难维护,改成嵌套的LEFT JOIN链后逻辑一目了然。
迁移过程中的注意事项与常见陷阱
第一,(+)不能和ANSI JOIN混用在同一条连接里,Oracle会抛出ORA-25156错误。因此迁移要么整条SQL一起改,要么暂时保持旧写法,不能只改一半。
第二,检查SELECT列表、ORDER BY里对从表列的NVL、DECODE等函数调用,确认重构后结果一致。特别是从表列上的聚合和去重逻辑,新旧语法在NULL处理上一致,但执行计划可能不同,建议在测试环境用MINUS双向比对结果集:
-- 双向比对两版本结果是否一致 SELECT * FROM old_query MINUS SELECT * FROM new_query UNION ALL SELECT * FROM new_query MINUS SELECT * FROM old_query;
第三,关注执行计划变化。绝大多数情况下ANSI写法性能相当甚至更好,优化器能生成更清晰的连接树;但在个别复杂多表外连接场景中,不同版本优化器可能选择不同计划,迁移后应使用DBMS_XPLAN对比。第四,别忘了视图和PL/SQL包里可能也藏着(+)语法,全局搜索一下再加号配合WHERE关键字,可以快速定位所有待改造的代码。
完成这轮重构后,SQL不仅在Oracle上运行,也能几乎原样迁移到PostgreSQL、MySQL等其他数据库,团队新人也能借助通用的JOIN语法快速理解查询意图,维护成本会显著降低。
Oracle外连接ANSI SQL JOIN(+)连接语法修改时间:2026-09-07 16:14:39