Oracle的加号(+)表示法和ansi JOIN符号之间的区别?

Fra*_*See 71 sql oracle performance join

使用oracle的加号(+)和ansi标准join符号之间的区别是什么?

性能有差异吗?

加号表示法是否已弃用?

nag*_*gul 97

AFAIK,该(+)符号仅用于向后兼容,因为Oracle在ANSI标准加入之前就推出了它.它特定于Oracle,当有可用的等效标准版本时,您应该避免在新代码中使用它.

编辑: 似乎两者之间存在差异,并且(+)符号具有ANSI连接语法所没有的限制.Oracle自己建议您不要使用(+)表示法.Oracle®数据库SQL语言参考11g第1版(11.1)中的完整描述:

Oracle建议您使用FROM子句OUTER JOIN语法而不是Oracle连接运算符.使用Oracle连接运算符的外连接查询(+)受以下规则和限制的约束,这些规则和限制不适用于FROM子句OUTER JOIN语法:

  • 您不能(+)在也包含FROM子句连接语法的查询块中指定运算符.
  • (+)操作者可以只出现在WHERE条款,或在左相关的上下文中(指定时TABLE的条款)FROM条款,并且只能被应用到的表或视图的一列.
  • 如果A和B通过多个连接条件连接,则必须(+)在所有这些条件下使用运算符.如果不这样做,那么Oracle数据库将仅返回由简单连接产生的行,但没有警告或错误,建议您没有外连接的结果.

  • (+),如果你在一个内部查询外部查询和其他表指定一个表操作不会产生一个外部联接.

  • (+)虽然自联接有效,但您无法使用运算符将表外连接到自身.

例如,以下语句无效:

SELECT employee_id, manager_id
FROM employees
WHERE employees.manager_id(+) = employees.employee_id;
Run Code Online (Sandbox Code Playgroud)

但是,以下自联接有效:

SELECT e1.employee_id, e1.manager_id, e2.employee_id
FROM employees e1, employees e2
WHERE e1.manager_id(+) = e2.employee_id;
Run Code Online (Sandbox Code Playgroud)
  • (+)操作员可以仅应用于一列,而不是任意表达式.但是,任意表达式可以包含一个或多个用(+)运算符标记的列.

  • WHERE包含(+)运算符的条件不能使用OR逻辑运算符与其他条件组合.

  • WHERE条件不能使用IN比较条件,比较标有一列(+)带表达式运算符.

如果WHERE子句包含将表B中的列与常量进行比较的条件,则(+)必须将该运算符应用于该列,以便Oracle从表A返回已为此列生成空值的行.否则,Oracle仅返回简单连接的结果.

在执行两个以上表对的外连接的查询中,单个表可以是仅针对另一个表的空生成表.因此,您不能将(+)运算符应用于A和B的连接条件中的B列以及B和C的连接条件.请参阅SELECT外连接的语法.


Ton*_*ler 12

从Oracle 10开始仍然支持该表示法(我相信11).它的使用被认为是"老式的",并且不像ANSI JOIN语法那样是数据库可移植的.它也被认为更不易读,虽然如果你来自+背景习惯ANSI JOIN可能需要一点时间.在向Oracle投掷砖块之前要知道的重要事项是,在ANSI委员会完成连接定义之前,他们开发了+语法.

没有性能差异; 他们表达了同样的话.

编辑:通过"不那么便携"我应该说"只在Oracle SQL中支持"

  • 但请注意,当使用ANSI语法时,Oracle优化器会生成错误的查询计划或不正确的结果,存在许多错误.这在11.1中比在10.1或10.2中更不常见,但它经常发生并且已经烧坏了足够的人,这些人是ANSI语法的早期采用者,Oracle社区的大部分人都对采用ANSI语法犹豫不决. (13认同)
  • 我有一个例子,你仍然被迫使用旧的Oracle连接语法:如果使用`FAST REFRESH`创建`MATERIALIZED VIEW`,则不能使用ANSI语法.我刚刚检查了Oracle页面这个问题,它仍然存在.Oracle不认为这是一个错误!有关详细信息,请参阅Oracle Doc ID 1372720.1,以防您有权访问Oracle支持. (6认同)

Vin*_*rat 12

我同意Tony Miller的回答,并想补充一点,你可以用(+)synthax做一些事情:

  • 你不能FULL OUTER JOIN两个表,你必须手动使用UNION ALL两个连接,
  • 你不能将表连接到两个或多个表,你必须手动创建一个子查询(即:b.id = a.id (+) AND c.id = a.id (+)不是一个可接受的子句)


sch*_*rer 11

最全面的答案显然是nagul的答案.

对于那些正在寻找快速转换/映射到ANSI语法的人的补充:

--
-- INNER JOIN
--
SELECT *
FROM EMP e
INNER JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

 -- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO = e.DEPTNO;

--
-- LEFT OUTER JOIN
--
SELECT *
FROM EMP e
LEFT JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

 -- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO (+) = e.DEPTNO;

--
-- RIGHT OUTER JOIN
--
SELECT *
FROM EMP e
RIGHT JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

-- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO = e.DEPTNO(+);

--
-- CROSS JOIN
--
SELECT *
FROM EMP e
CROSS JOIN DEPT d;

 -- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d;

--
-- FULL JOIN
--
SELECT *
FROM EMP e
FULL JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

-- Synonym in deprecated oracle (+) syntax !NOT WORKING!
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO (+) = e.DEPTNO(+);
Run Code Online (Sandbox Code Playgroud)


Lal*_*r B 5

使用ANSI语法而不是旧的Oracle 连接语法的充分理由之一是,意外创建笛卡尔积的可能性为零。如果表数量较多,则有可能会错过使用较旧的 Oracle 连接语法的隐式连接,但是,使用 ANSI 语法,您不能错过任何连接,因为您必须这样做显式提及它们。

Oracle 外连接语法ANSI/ISO 语法之间的差异。

左外连接 -

SELECT e.last_name,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id = d.department_id(+);

SELECT e.last_name,
  d.department_name
FROM employees e
LEFT OUTER JOIN departments d
ON (e.department_id = d.department_id);
Run Code Online (Sandbox Code Playgroud)

右外连接 -

SELECT e.last_name,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id(+) = d.department_id;

SELECT e.last_name,
  d.department_name
FROM employees e
RIGHT OUTER JOIN departments d
ON (e.department_id = d.department_id);
Run Code Online (Sandbox Code Playgroud)

全外连接 -

在 11gR1 原生支持哈希完整外连接之前,Oracle 将按以下方式在内部转换 FULL OUTER JOIN -

SELECT e.last_name,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id = d.department_id(+)
UNION ALL
SELECT NULL,
  d.department_name
FROM departments d
WHERE NOT EXISTS
  (SELECT 1 FROM employees e WHERE e.department_id = d.department_id
  );

SELECT e.last_name,
  d.department_name
FROM employees e
FULL OUTER JOIN departments d
ON (e.department_id = d.department_id);
Run Code Online (Sandbox Code Playgroud)

看看这个