繁体   English   中英

左外连接使用 + 登录 Oracle 11g

[英]Left Outer Join using + sign in Oracle 11g

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

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

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

SELECT P.Part_Id, S.Supplier_Name
FROM Part P, Supplier S
WHERE P.Supplier_Id = S.Supplier_Id (+)

SELECT P.Part_Id, S.Supplier_Name
FROM Part P, Supplier S
WHERE S.Supplier_Id (+) = P.Supplier_Id

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 S中, P将始终有一条记录,因为它在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。 (具体来说,如果(+)在右侧,则为 LEFT JOIN。如果(+)在左侧,则为 RIGHT JOIN。)


JOIN的类型

JOIN 的两个 styles 是隐式 JOIN显式 JOIN 它们是写JOIN的不同styles,但功能上是等价的。

请参阅这个 SO 问题

隐式 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

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

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

Oracle 建议您使用 FROM 子句 OUTER JOIN 语法,而不是 Oracle 连接运算符。 使用 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

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

左外连接

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

右外连接

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

左外连接

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

右外连接

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

You can see answers from previous posts
However I added little more information 
    create table r2020 (id int, name varchar2(50),rank number);
    insert into r2020 values (101,'Rob Rama',1);
    insert into r2020 values (102,'Ken Krishna',3);
    insert into r2020 values (108,'Ray Rama',2);
    insert into r2020 values (109,'Kat Krishna',4);
    
    create table r2021 (id int, name varchar2(50),rank number);
    insert into r2021 values (102,'Ken Krishna',1); 
    insert into r2021 values (103,'Tom Talla',2);
    insert into r2021 values (108,'Ray Rama',2); 
    
    --LEFT OUTER JOIN  
        --oracle notation
        select * from r2020 r1, r2021 r2
        where  r1.id  = r2.id (+) 
        order by r1.id;
        
        --ANSI notation
        select * from r2020 r1
        left outer join r2021 r2 on  r1.id = r2.id  
        order by r1.id;
        --OUT PUT
        NAME        ID RANK  NAME_1     ID_1    RANK_1
        ----        -- ---- ----        ----   ------
        Rob Rama    101 1   (null)      (null)  (null)
        Ken Krishna 102 3   Ken Krishna 102     1
        Ray Rama    108 2   Ray Rama    108     2
        Kat Krishna 109 4   (null)      (null)  (null)
    
    --RIGHT OUTER JOIN  
        --oracle notation
        select * from r2020 r1, r2021 r2
        where  r1.id (+)  = r2.id 
        order by r1.id;
        
        --ANSI notation
        select * from r2020 r1
        right outer join r2021 r2 on  r1.id = r2.id  
        order by r1.id;
        --OUT PUT
        NAME        ID    RANK    NAME_1      ID_1    RANK_1
        ----        --    ----    ----        ----   ------
        Ken Krishna 102     3     Ken Krishna 102    1
        Ray Rama    108     2     Ray Rama    108    2
        (null)      (null) (null) Tom Talla   103    2
        
        
    --<b>MULTIPLE COLUMNS IN JOIN CONDITION</b>
    --LEFT OUTER JOIN  
        --oracle notation
        select * from r2020 r1, r2021 r2
        where  r1.id  = r2.id (+) and 
               r1.rank  = r2.rank (+)
        order by r1.id;
        
        --ANSI notation
        select * from r2020 r1
        left outer join r2021 r2 on  r1.id = r2.id and 
                                     r1.rank  = r2.rank 
        order by r1.id;
        --OUT PUT
        NAME        ID RANK  NAME_1     ID_1    RANK_1
        ----        -- ---- ----        ----   ------
        Rob Rama    101 1   (null)      (null)  (null)
        Ken Krishna 102 3   (null)      (null)  (null)
        Ray Rama    108 2   Ray Rama    108     2
        Kat Krishna 109 4   (null)      (null)  (null)
    
    --RIGHT OUTER JOIN  
        --oracle notation
        select * from r2020 r1, r2021 r2
        where  r1.id (+)  = r2.id and
               r1.rank(+)  = r2.rank 
        order by r1.id;
        
        --ANSI notation
        select * from r2020 r1
        right outer join r2021 r2 on  r1.id = r2.id and
                                      r1.rank  = r2.rank 
        order by r1.id;
        --OUT PUT
        NAME      ID     RANK   NAME_1       ID_1  RANK_1
        ----      --     ----   ----         ----  ------
        (null)    (null) (null) Ken Krishna  102   1
        Ray Rama  108     2     Ray Rama     108   2
        (null)    (null) (null) Tom Talla    103   2

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

左外连接

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

右外连接

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

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

Oracle OCP Oracle 9i 简介:SQL 考试指南 第 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

请注意,这与上面发布的内容相反。 我想这本书可能有勘误表,但是我更相信这本书而不是这个线程中的内容。 这是大声哭泣的考试指南...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM