在进行数据库迁移或兼容性开发时,您可能会遇到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来启用此功能。说明此参数可在会话级、用户级或数据库级进行设置。同时,亦支持在控制台的参数模板中进行全局配置。