在Oracle 11g中使用+登录进行左外部联接


80

谁能告诉我以下两个查询是“左外部连接”还是“右外部连接”的示例?

Table Part:
Name         Null?       Type
PART_ID      NOT NULL    VARCHAR2(4)
SUPPLIER_ID              VARCHAR2(4)

PART_ID SUPPLIER_ID
P1      S1
P2      S2
P3  
P4  

Table Supplier:
Name            Null?     Type
SUPPLIER_ID NOT NULL      VARCHAR2(4)
SUPPLIER_NAME   NOT NULL  VARCHAR2(20)

SUPPLIER_ID  SUPPLIER_NAME
S1           Supplier#1
S2           Supplier#2
S3           Supplier#3

显示所有零件,无论是否有供应商提供它们:

选择P.Part_Id,S.Supplier_Name
从供应商S的P部分开始
W.P.Supplier_Id = S.Supplier_Id(+)

选择P.Part_Id,S.Supplier_Name
从供应商S的P部分开始
W.S.Supplier_Id(+)= P.Supplier_Id

26
您应该避免使用“(+)”符号,并将查询升级为使用显式联接。
乔纳森·勒夫勒

1
@JonathanLeffler 100%同意。问题是我与不愿使用标准符号的人一起工作。我用标准符号编写新查询,但是如果修改了旧查询,我将在一分钟内将其开枪。
Luc M

3
@JonathanLeffler我同意,除非您使用Oracle。目前的Oracle不能在内部处理ansi语法以及(+)运算符。尽管他们确实建议使用ansi语法:) docs.oracle.com/cd/B28359_01/server.111/b28286/queries006.htm
神话

7
@Amyth对不起,这种方式已经过时了,但我是通过搜索找到这个问题的。就我自己而言,我完全相反地理解Oracle的建议。通过链接:Oracle建议您使用FROM子句OUTER JOIN语法而不是Oracle联接运算符。使用Oracle联接运算符(+)的外部联接查询应遵循以下规则和限制,不适用于以下规则和限制: FROM子句OUTER JOIN语法...“
Sylvain Leroux 2014年

对于过时的响应也很抱歉:),但是Oracle所说的话,以及它的统计信息如何优化查询是两件不同的事,这可能是Oracle改变了立场,并随着内部优化器的发展而改变了
神话

Answers:


186

TableA LEFT OUTER JOIN TableB等价于TableB RIGHT OUTER JOIN Table A

在Oracle中,(+)表示JOIN中的“可选”表。因此,在您的第一个查询中,它是一个P LEFT OUTER JOIN S。在第二个查询中,它是S RIGHT OUTER JOIN P它们在功能上是等效的。

在术语中,RIGHT或LEFT指定连接的哪一侧总是有记录,而另一侧可能为null。因此,在中P LEFT OUTER JOIN SP将始终有一条记录,因为它在上LEFT,但S可以为null。

有关更多说明,请参见java2s.com上的示例。


为了澄清起见,我想我是说术语并不重要,因为它仅用于可视化。重要的是您了解其工作原理。


右与左

对于在隐式连接语法中确定RIGHT与LEFT的关系,我已经看到了一些困惑。

左外连接

SELECT *
FROM A, B
WHERE A.column = B.column(+)

右外连接

SELECT *
FROM A, B
WHERE B.column(+) = A.column

我所做的只是WHERE子句中条款的互换面,但它们在功能上仍然等效。(有关此问题的更多信息,请参见我的答案的较高部分。)(+)确定RIGHT或LEFT的位置。(特别是,如果在(+)右侧,则为“左联接”。如果(+)在左侧,则为“右联接”。)


JOIN的类型

JOIN的两种样式是隐式JOIN显式JOIN。它们是编写JOIN的不同样式,但是在功能上是等效的。

看到这个问题

隐式联接只是将所有表一起列出。连接条件在WHERE子句中指定。

隐式加入

SELECT *
FROM A, B
WHERE A.column = B.column(+)

显式JOIN将联接条件与特定表的包含而不是WHERE子句相关联。

显式加入

SELECT *
FROM A
LEFT OUTER JOIN B ON A.column = B.column

这些隐式JOIN可能更难以阅读和理解,并且由于在其他WHERE条件中混合了联接条件,因此它们也有一些限制。因此,通常建议不要使用隐式JOIN,而应使用显式语法。


3
是的,我现在明白了-JOIN是通过(+)的存在隐式创建的。凉。
Kerrek SB 2011年

2
@Mike:这就是+语法的工作方式。它的意思是“可选”,因此应像“列出所有零件,可选地使供应商匹配”那样阅读。
Kerrek SB 2011年

2
@Mike:只要您知道要选择的内容,如何调用它就无关紧要。但是请帮个忙,改用惯用JOIN语法!这样就不会有混乱的余地了。
Kerrek SB 2011年

1
@TomJMuthirenthi如果不使用显式FULL OUTER JOIN语法,则需要将UNION [ALL]两个结果集放在一起:一个用于A = B(+),一个用于B = A(+)。这个问题的例子。
Wiseguy

1
“(+)”位于生成空子行的表的列上。
philipxy

9

这两个查询正在执行OUTER JOIN。见下文

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

  • 您不能在还包含FROM子句联接语法的查询块中指定(+)运算符。

  • (+)运算符只能出现在WHERE子句中,或者出现在FROM子句的左相关(指定TABLE子句时)的上下文中,并且只能应用于表或视图的列。

  • 如果A和B通过多个联接条件联接,则必须在所有这些条件中使用(+)运算符。如果不这样做,那么Oracle数据库将仅返回由简单联接产生的行,而不会发出警告或错误,以提醒您没有外部联接的结果。

  • 如果在外部查询中指定一个表,而在内部查询中指定另一个表,则(+)运算符不会产生外部联接。

  • 尽管自联接有效,但是不能使用(+)运算符将表外部联接到自身。例如,以下语句无效:

    -- The following statement is not valid:
    SELECT employee_id, manager_id
       FROM employees
       WHERE employees.manager_id(+) = employees.employee_id;
    

    但是,以下自我联接是有效的:

    SELECT e1.employee_id, e1.manager_id, e2.employee_id
       FROM employees e1, employees e2
       WHERE e1.manager_id(+) = e2.employee_id
       ORDER BY e1.employee_id, e1.manager_id, e2.employee_id;
    
  • (+)运算符只能应用于列,不能应用于任意表达式。但是,任意表达式可以包含一个或多个标有(+)运算符的列。

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

  • WHERE条件不能使用IN比较条件将标有(+)运算符的列与表达式进行比较。

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

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

取自http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/queries006.htm


2

我在上面的答案中看到了一些矛盾,我只是在Oracle 12c上尝试了以下方法,以下是正确的:

左外连接

SELECT *
FROM A, B
WHERE A.column = B.column(+)

右外连接

SELECT *
FROM A, B
WHERE B.column(+) = A.column


-2

此线程中有一些不正确的信息。我复制并粘贴了不正确的信息:

左外连接

SELECT *
FROM A, B
WHERE A.column = B.column(+)

右外连接

SELECT *
FROM A, B
WHERE B.column(+) = A.column

以上是错误的!!!!! 这是相反的。我如何确定这是不正确的,来自以下书籍:

Oracle OCP Oracle 9i简介:SQL考试指南。Page 115表3-1对此做了很好的总结。我无法弄清楚为什么转换后的SQL不能正常工作,直到我上了高中并看了一本印刷书籍!

这是本书的摘要,逐行复制:

Oracle外连接语法:

from tab_a a, tab_b b,                                       
where a.col_1 + = b.col_1                                     

相当于ANSI / ISO:

from tab_a a left outer join  
tab_b b on a.col_1 = b.col_1

请注意,这与上面发布的内容相反。我想这本书可能有勘误表,但是我比这本书中的内容更相信这本书。这是大声喊叫的考试指南...


4
这与我在答案中链接的内容相矛盾,答案是从Oracle数据库10g SQL(Osborne ORACLE新闻系列)第一版(2004年2月20日)中摘录的,其中指出:“在左外部联接中,外部联接运算符实际上是在平等经营者的权利。” 这是您的示例的演示。结果a.col_1(+) = b.col_1比赛RIGHT JOIN,而不是LEFT JOIN。
Wiseguy 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.