Левое внешнее объединение с помощью знака + в 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
ОТ Часть P, Поставщик S
ГДЕ P.Supplier_Id = S.Supplier_Id (+)

SELECT P.Part_Id, S.Supplier_Name
ОТ Часть P, Поставщик S
ГДЕ S.Supplier_Id (+) = P.Supplier_Id

Спасибо!

7 ответов

Решение

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 указывают, какая сторона объединения всегда имеет запись, а другая сторона может быть нулевой. Так что в P LEFT OUTER JOIN S, P всегда будет иметь запись, потому что это на LEFT, но S может быть нулевым.

Посмотрите этот пример от java2s.com для дополнительного объяснения.


Чтобы уточнить, я полагаю, я говорю, что терминология не имеет значения, так как она используется только для визуализации. Важно то, что вы понимаете, как это работает.


ПРАВО против ЛЕВОГО

Я видел некоторую путаницу в том, что имеет значение при определении ПРАВО против ЛЕВЫХ в неявном синтаксисе соединения.

ЛЕВОЕ НАРУЖНОЕ СОЕДИНЕНИЕ

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

ПРАВО НАРУЖНОЕ СОЕДИНЕНИЕ

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

Все, что я сделал, это поменялся сторонами терминов в предложении WHERE, но они все еще функционально эквивалентны. (См. Выше в моем ответе для получения дополнительной информации об этом.) Размещение (+) определяет ПРАВО или ВЛЕВО. (В частности, если (+) справа, это левое соединение. Если (+) слева, это ПРАВИЛЬНОЕ СОЕДИНЕНИЕ.)


Типы JOIN

Два стиля JOIN - это неявные соединения и явные соединения. Это разные стили написания JOIN, но они функционально эквивалентны.

Смотри этот ТАК вопрос.

Неявные соединения просто перечисляют все таблицы вместе. Условия соединения указаны в предложении WHERE.

Неявное СОЕДИНЕНИЕ

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

Явные СОЕДИНЕНИЯ связывают условия соединения с включением определенной таблицы, а не в предложении WHERE.

Явное ПРИСОЕДИНЕНИЕ

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

Эти неявные соединения могут быть более трудными для чтения и понимания, и они также имеют несколько ограничений, так как условия соединения смешаны в других условиях WHERE. Таким образом, неявные соединения обычно рекомендуются в пользу явного синтаксиса.

Эти два запроса выполняются OUTER JOIN, Увидеть ниже

Oracle рекомендует использовать синтаксис OUTER JOIN предложения FROM, а не оператор соединения Oracle. На запросы внешнего соединения, использующие оператор соединения Oracle (+), распространяются следующие правила и ограничения, которые не применяются к синтаксису OUTTER JOIN предложения FROM:

  • Вы не можете указать оператор (+) в блоке запроса, который также содержит синтаксис соединения предложения FROM.

  • Оператор (+) может появляться только в предложении WHERE или в контексте левой корреляции (при указании предложения TABLE) в предложении FROM и может применяться только к столбцу таблицы или представления.

  • Если A и B объединяются несколькими условиями соединения, то вы должны использовать оператор (+) во всех этих условиях. Если вы этого не сделаете, то Oracle Database вернет только строки, полученные в результате простого объединения, но без предупреждения или ошибки, сообщив вам, что у вас нет результатов внешнего соединения.

  • Оператор (+) не создает внешнее соединение, если вы указываете одну таблицу во внешнем запросе, а другую таблицу - во внутреннем запросе.

  • Вы не можете использовать оператор (+) для внешнего соединения таблицы с самим собой, хотя самостоятельные объединения допустимы. Например, следующее утверждение недопустимо:

    -- 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 возвращает только результаты простого объединения.

В запросе, который выполняет внешние объединения более двух пар таблиц, одна таблица может быть сгенерированной нулем только для одной другой таблицы. По этой причине вы не можете применить оператор (+) к столбцам B в условии соединения для A и B и в условии соединения для B и C. Обратитесь к 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

ЛЕВОЕ НАРУЖНОЕ СОЕДИНЕНИЕ

ВЫБРАТЬ * ИЗ A, B, ГДЕ A.column = B.column(+)

ПРАВО НАРУЖНОЕ СОЕДИНЕНИЕ

ВЫБРАТЬ * ИЗ A, B, ГДЕ 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

Чтобы написать запрос, который выполняет внешнее соединение таблиц A и B и возвращает все строки из A (левое внешнее соединение), используйте синтаксис LEFT [OUTER] JOIN в предложении FROM или примените оператор внешнего соединения (+) к все столбцы B в условии соединения в предложении WHERE

В этой теме есть неверная информация. Я скопировал и вставил неверную информацию:

ЛЕВОЕ НАРУЖНОЕ СОЕДИНЕНИЕ

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

ПРАВО НАРУЖНОЕ СОЕДИНЕНИЕ

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

Выше НЕПРАВИЛЬНО!!!!! Оно задом наперед. Как я определил, что это неверно, из следующей книги:

Oracle OCP Введение в Oracle 9i: Руководство по экзамену SQL. Таблица 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

Обратите внимание, что это обратное тому, что написано выше. Я полагаю, что в этой книге могут быть ошибки, однако я доверяю этой книге больше, чем тому, что есть в этой теме. Это руководство к экзамену для громкого крика...

Другие вопросы по тегам