在进行数据库迁移或兼容性开发时,您可能会遇到Oracle特有的(+)
外连接语法。这种语法在WHERE
子句中通过在列名后添加(+)
符号来表示外连接,与标准的LEFT JOIN
或RIGHT JOIN
语法不同。为了帮助您理解和使用这种传统语法,PolarDB PostgreSQL版(兼容Oracle)提供了对(+)
操作符的兼容支持,确保既有代码能够平滑迁移和运行。
功能简介
(+)
操作符是Oracle数据库中用于实现外连接(Outer Join)的一种传统语法。它通过在WHERE
子句的连接条件中,将(+)
符号放置在需要补足NULL
值的表的列名一侧,来定义左外连接或右外连接。
左外连接(LEFT OUTER JOIN)
将(+)
放在右表(需要补NULL
的表)的连接列上。SELECT columns FROM table1, table2 WHERE table1.column = table2.column(+);
这等效于标准的SQL语法:
SELECT columns FROM table1 LEFT JOIN table2 ON table1.column = table2.column;
右外连接(RIGHT OUTER JOIN)
将(+)
放在左表(需要补NULL
的表)的连接列上。SELECT columns FROM table1, table2 WHERE table1.column(+) = table2.column;
这等效于标准的SQL语法:
SELECT columns FROM table1 RIGHT JOIN table2 ON table1.column = table2.column;
注意事项
(+)
操作符只能出现在WHERE
子句中,不能出现在ON
子句中。一个连接条件中,
(+)
操作符只能出现在等号的一侧。在一个查询中,同一个表的多个连接条件需一致地使用(+)
。包含
(+)
的连接条件不能与其他条件通过OR
逻辑运算符组合。虽然PolarDB PostgreSQL版(兼容Oracle)支持
(+)
语法,但为了更好的可读性和跨数据库兼容性,建议在新项目中优先使用标准的LEFT JOIN
和RIGHT JOIN
语法。
使用示例
以下示例将演示(+)
操作符的常见用法。
准备数据
在执行示例前,请先连接到您的PolarDB集群并创建以下测试表。
-- 创建员工表
CREATE TABLE emp (
empno NUMBER(4) PRIMARY KEY,
ename VARCHAR2(20),
deptno NUMBER(2),
sal NUMBER(7,2)
);
-- 创建部门表
CREATE TABLE dept (
deptno NUMBER(2) PRIMARY KEY,
dname VARCHAR2(20),
loc VARCHAR2(20)
);
-- 插入部门数据
INSERT INTO dept VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO dept VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO dept VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO dept VALUES (40, 'OPERATIONS', 'BOSTON'); -- 这是一个没有员工的部门
-- 插入员工数据
INSERT INTO emp VALUES (7369, 'SMITH', 20, 800);
INSERT INTO emp VALUES (7499, 'ALLEN', 30, 1600);
INSERT INTO emp VALUES (7782, 'CLARK', 10, 2450);
INSERT INTO emp VALUES (7839, 'KING', 10, 5000);
INSERT INTO emp VALUES (8000, 'TEMP', NULL, 1000); -- 这是一个没有部门的员工
COMMIT;
示例1:实现左外连接
查询所有员工及其部门信息。即使某些员工没有分配部门(即deptno
为NULL
),也需要将这些员工包含在结果中。
-- 使用(+)实现左外连接,(+)放在右表(dept)的列上
SELECT e.ename, e.sal, d.dname, d.loc
FROM emp e, dept d
WHERE e.deptno = d.deptno(+)
ORDER BY e.empno;
返回结果:
ename | sal | dname | loc
-------+------+------------+----------
SMITH | 800 | RESEARCH | DALLAS
ALLEN | 1600 | SALES | CHICAGO
CLARK | 2450 | ACCOUNTING | NEW YORK
KING | 5000 | ACCOUNTING | NEW YORK
TEMP | 1000 | |
(5 rows)
结果说明:
查询结果会包含所有emp
表中的员工。对于名为TEMP
的员工,由于其deptno
为NULL
,无法在dept
表中找到匹配项,因此对应的d.dname
和d.loc
列将显示为NULL
。
示例2:实现右外连接
查询所有部门及其员工信息。即使某些部门下没有员工,也需要将这些部门包含在结果中。
-- 使用(+)实现右外连接,(+)放在左表(emp)的列上
SELECT e.ename, e.sal, d.dname, d.loc
FROM emp e, dept d
WHERE e.deptno(+) = d.deptno
ORDER BY d.deptno, e.ename;
返回结果:
ename | sal | dname | loc
-------+------+------------+----------
CLARK | 2450 | ACCOUNTING | NEW YORK
KING | 5000 | ACCOUNTING | NEW YORK
SMITH | 800 | RESEARCH | DALLAS
ALLEN | 1600 | SALES | CHICAGO
| | OPERATIONS | BOSTON
(5 rows)
结果说明:
查询结果会包含所有dept
表中的部门。对于名为OPERATIONS
的部门,由于没有员工属于该部门,因此对应的e.ename
和e.sal
列将显示为NULL
。
示例3:在聚合查询中使用
(+)
操作符同样可以用于聚合查询,例如统计每个部门的员工数量,包括那些没有员工的部门。
-- 统计各部门的员工数量,包括空部门
SELECT d.dname, COUNT(e.empno) AS emp_count
FROM dept d, emp e
WHERE d.deptno = e.deptno(+)
GROUP BY d.dname, d.deptno
ORDER BY d.deptno;
返回结果:
dname | emp_count
------------+-----------
ACCOUNTING | 2
RESEARCH | 1
SALES | 1
OPERATIONS | 0
(4 rows)
结果说明:
对于OPERATIONS
部门,由于没有匹配的员工,COUNT(e.empno)
的结果将为0
。
兼容性说明
在Oracle 19c及更高版本中,支持在WHERE
子句中对多个表同时使用(+)
操作符进行外连接。例如:
SELECT e.ename, d.dname, e.sal, s.grade
FROM emp e, dept d, salgrade s
WHERE e.deptno(+) = d.deptno AND e.sal(+) = s.hisal;
在PolarDB PostgreSQL版(兼容Oracle)中,不同内核版本的处理方式不同:
修订版本小于2.0.14.17.36.0:不支持。
修订版本大于等于2.0.14.17.36.0:您可以通过设置参数
polar_enable_transform_new_style_join_expr
来启用此功能。说明此参数可在会话级、用户级或数据库级进行设置。同时,亦支持在控制台的参数模板中进行全局配置。