在维护老旧系统时,常会见到使用(+)运算符的SQL查询语句。这种写法是Oracle独有的旧式连接语法,用于实现左连接或右连接操作。一个关键细节是:利用(+)实现右连接时,必须将(+)放在等号左侧的列上,并且整个查询需采用旧式的逗号语法(即隐式连接)。若混用JOIN关键字,或遗漏了某个条件的(+),都可能导致错误或逻辑异常。

为什么必须把(+)放在左边?
这取决于Oracle对(+)运算符的设计理念。(+)本质上是一个“补全”标记,它所标注的一侧表是被限制匹配的表,而另一侧的表则会被无条件保留。因此,当编写a.id(+) = b.id时,b表的所有行都会出现在结果集中,a表仅返回能匹配b.id的行,未匹配的则填充NULL——这正是右连接的语义。
a.id = b.id(+)→ 左连接(a表所有行保留)a.id(+) = b.id→ 右连接(b表所有行保留)a.id(+) = b.id(+)→ 语法错误,不允许同时在两侧添加(+)
千万别混搭:逗号语法与JOIN不兼容
(+)是Oracle 9i之前的遗留语法,与标准的LEFT JOIN、RIGHT JOIN属于完全不同的体系。如果在代码中使用了JOIN关键字,同时又添加了(+),Oracle解析器会直接报错ORA-00905: missing keyword,或解析失败。简言之,这两种写法互不兼容。
- ✅ 正确的写法:
SELECT * FROM emp, dept WHERE emp.deptno(+) = dept.deptno - ❌ 错误的写法:
SELECT * FROM emp RIGHT JOIN dept ON emp.deptno(+) = dept.deptno - ❌ 另一种常见错误:
SELECT * FROM emp, dept WHERE emp.deptno(+) = dept.deptno AND emp.ename LIKE '%A%'— 此处遗漏了(+),实际上会导致部分关联条件的效果丢失。
多条件时,(+)必须全覆盖
若WHERE子句包含多个表间的关联条件,务必在每个条件的“从表列”上添加(+)。否则,整个外连接的逻辑将失效,可能退化为内连接。
- 假设要连接
emp、dept、loc三张表,且希望loc表全部保留: - ✅ 正确形式:
WHERE dept.loc = loc.loc_id(+) AND emp.deptno = dept.deptno(+) - ❌ 错误形式:少了一个
(+):WHERE dept.loc = loc.loc_id(+) AND emp.deptno = dept.deptno— 此时dept表的外连接效果丢失,loc的补全作用也会被连带破坏。 - 另外有一点:
(+)不能用在表达式里。比如UPPER(emp.ename)(+) = 'SMITH'会直接报错ORA-00920: invalid relational operator。
12c+环境下的兼容性陷阱
尽管(+)语法在Oracle 12c及后续版本中仍可运行,但官方已明确将其标记为“deprecated”(已弃用)。在复杂查询中(如包含子查询、WITH子句、分析函数等),它更容易引发解析异常或执行计划偏差。实际迁移时,最常见的陷阱并非语法错误,而是(+)与AND条件顺序导致的过滤提前。例如,将AND emp.sal > 2000放在(+)条件之后,会导致Oracle先过滤数据再执行外连接,结果与预期大相径庭。
真正棘手的是混合场景:老旧系统中的SQL嵌套层次深、别名繁多,再加上ORDER BY子句,此时(+)的作用域边界会变得异常模糊。与其在这种环境下纠结,不如直接将其重写为RIGHT JOIN,这样更易于控制。
