Left Outer Join za pomocą + Zaloguj się w Oracle 11g


81

Czy ktoś może mi powiedzieć, czy poniżej 2 zapytań są przykładem Left Outer Join lub Right Outer Join?

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

Wyświetl wszystkie części niezależnie od tego, czy dostawca je dostarcza, czy nie:

SELECT P.Part_Id, S.Supplier_Name
Z Części P, Dostawca S
GDZIE P.Supplier_Id = S.Supplier_Id (+)

SELECT P.Part_Id, S.Supplier_Name
Z Części P, Dostawca S
GDZIE S.Supplier_Id (+) = P.Supplier_Id

26
Należy unikać używania notacji „(+)” i zaktualizować zapytania, aby używały jawnych złączeń.
Jonathan Leffler

1
@JonathanLeffler W 100% zgadzam się. Problem w tym, że pracuję z ludźmi, którzy nie chcą przełączyć się na notację standardową. Piszę nowe zapytanie ze standardową notacją, ale za minutę będę strzelał, jeśli zmodyfikuje stary.
Luc M

3
@JonathanLeffler Zgadzam się, chyba że używasz Oracle. Obecnie Oracle nie obsługuje składni ansi ani operatora (+) wewnętrznie. Chociaż zalecają używanie składni ansi :) docs.oracle.com/cd/B28359_01/server.111/b28286/queries006.htm
Mit

7
@Amyth Przepraszam za taki nieaktualny komentarz, ale doszedłem do tego pytania z wyszukiwania. Ja sam rozumiem zalecenia Oracle w dokładnie odwrotny sposób. Z Twojego linku: Firma Oracle zaleca używanie składni FROM klauzuli OUTER JOIN zamiast operatora łączenia Oracle. Zapytania o sprzężenie zewnętrzne korzystające z operatora łączenia Oracle (+) podlegają następującym regułom i ograniczeniom, które nie mają zastosowania do FROM klauzula OUTER JOIN składnia ... ”
Sylvain Leroux,

Przepraszam za nieaktualną odpowiedź :), ale to, co mówi Oracle i jak jego statystyki działają w celu optymalizacji zapytań, to dwie różne rzeczy i może być tak, że Oracle zmienił również swoje stanowisko wraz z postępami w zakresie wewnętrznych optymalizatorów
mit

Odpowiedzi:


188

TableA LEFT OUTER JOIN TableBjest równoważne TableB RIGHT OUTER JOIN Table A.

W Oracle (+)oznacza „opcjonalną” tabelę w JOIN. Więc w pierwszym zapytaniu jest to plik P LEFT OUTER JOIN S. W drugim zapytaniu to S RIGHT OUTER JOIN P. Są funkcjonalnie równoważne.

W terminologii PRAWO lub LEWO określ, która strona sprzężenia zawsze ma rekord, a druga strona może być zerowa. Więc w a P LEFT OUTER JOIN S, Pzawsze będzie miał rekord, ponieważ jest na LEFT, ale Smoże być pusty.

Dodatkowe wyjaśnienia można znaleźć w przykładzie z witryny java2s.com .


Aby wyjaśnić, myślę, że mówię, że terminologia nie ma znaczenia, ponieważ służy tylko do wizualizacji. Liczy się to, że rozumiesz koncepcję tego, jak to działa.


PRAWO vs LEWO

Widziałem pewne zamieszanie dotyczące tego, co ma znaczenie przy określaniu PRAWEGO i LEWEGO w niejawnej składni sprzężenia.

LEWE POŁĄCZENIE ZEWNĘTRZNE

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

PRAWE POŁĄCZENIE ZEWNĘTRZNE

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

Wszystko, co zrobiłem, to zamienić strony terminów w klauzuli WHERE, ale nadal są one funkcjonalnie równoważne. (Zobacz wyżej w mojej odpowiedzi, aby uzyskać więcej informacji na ten temat.) Umiejscowienie (+)określa PRAWO lub LEWO. (W szczególności, jeśli (+)znajduje się po prawej stronie, jest to LEWE POŁĄCZENIE. Jeśli (+)jest po lewej stronie, jest to PRAWE POŁĄCZENIE).


Rodzaje JOIN

Dwa style JOIN to niejawne JOIN i jawne JOIN . Są to różne style pisania JOIN, ale są one funkcjonalnie równoważne.

Zobacz to pytanie SO .

Niejawne JOIN po prostu wyświetlają wszystkie tabele razem. Warunki łączenia są określone w klauzuli WHERE.

Niejawne JOIN

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

Jawne JOIN kojarzą warunki łączenia z włączeniem konkretnej tabeli zamiast z klauzulą ​​WHERE.

Wyraźne JOIN

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

Te niejawne JOIN mogą być trudniejsze do odczytania i zrozumienia, a także mają kilka ograniczeń, ponieważ warunki łączenia są mieszane w innych warunkach WHERE. W związku z tym niejawne JOIN są generalnie zalecane na rzecz jawnej składni.


3
Racja, rozumiem to teraz - JOIN jest tworzony niejawnie przez obecność (+). Fajne.
Kerrek SB,

2
@Mike: Tak działa składnia +. Oznacza to „opcjonalne”, więc przeczytaj to jak „Wyświetl wszystkie części, opcjonalnie dopasuj dostawcę”.
Kerrek SB,

2
@Mike: Dopóki wiesz, co wybierasz, nie ma znaczenia, jak to nazwiesz. Ale zrób sobie przysługę i JOINzamiast tego użyj idiomatycznej składni! Wtedy nie ma miejsca na zamieszanie.
Kerrek SB,

1
@TomJMuthirenthi Bez używania jawnej FULL OUTER JOINskładni będziesz potrzebować UNION [ALL]dwóch zestawów wyników: jednego dla A = B (+) i jednego dla B = A (+). Przykład w tym pytaniu .
Wiseguy

1
Znak „(+)” przechodzi do kolumn tabeli, która generuje podrzędy z wartościami zerowymi.
philipxy

9

Te dwa zapytania działają OUTER JOIN. Zobacz poniżej

Firma Oracle zaleca użycie składni klauzuli FROM OUTER JOIN zamiast operatora łączenia Oracle. Zapytania sprzężenia zewnętrznego, które używają operatora sprzężenia Oracle (+), podlegają następującym regułom i ograniczeniom, które nie mają zastosowania do składni klauzuli FROM OUTER JOIN:

  • Nie można określić operatora (+) w bloku zapytania, który zawiera również składnię łączenia klauzuli FROM.

  • Operator (+) może występować tylko w klauzuli WHERE lub w kontekście lewostronnej korelacji (przy określaniu klauzuli TABLE) w klauzuli FROM i może być stosowany tylko do kolumny tabeli lub widoku.

  • Jeśli A i B są połączone wieloma warunkami złączenia, we wszystkich tych warunkach należy użyć operatora (+). Jeśli tego nie zrobisz, Oracle Database zwróci tylko wiersze wynikające z prostego sprzężenia, ale bez ostrzeżenia lub błędu informującego, że nie masz wyników sprzężenia zewnętrznego.

  • Operator (+) nie tworzy sprzężenia zewnętrznego, jeśli określisz jedną tabelę w zapytaniu zewnętrznym, a drugą tabelę w zapytaniu wewnętrznym.

  • Nie można użyć operatora (+), aby połączyć zewnętrznie tabelę z samą sobą, chociaż łączenia własne są prawidłowe. Na przykład poniższa instrukcja jest nieprawidłowa:

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

    Jednak następujące łączenie własne jest prawidłowe:

    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;
    
  • Operator (+) można zastosować tylko do kolumny, a nie do dowolnego wyrażenia. Jednak dowolne wyrażenie może zawierać jedną lub więcej kolumn oznaczonych operatorem (+).

  • Warunek WHERE zawierający operator (+) nie może być łączony z innym warunkiem przy użyciu operatora logicznego OR.

  • Warunek WHERE nie może używać warunku porównania IN do porównywania kolumny oznaczonej operatorem (+) z wyrażeniem.

Jeśli klauzula WHERE zawiera warunek porównujący kolumnę z tabeli B ze stałą, to operator (+) musi zostać zastosowany do kolumny, aby Oracle zwrócił wiersze z tabeli A, dla których wygenerował wartości null dla tej kolumny. W przeciwnym razie Oracle zwraca tylko wyniki prostego sprzężenia.

W zapytaniu, które wykonuje zewnętrzne łączenia więcej niż dwóch par tabel, pojedyncza tabela może być tabelą wygenerowaną przez wartość null tylko dla jednej innej tabeli. Z tego powodu nie można zastosować operatora (+) do kolumn B w warunku sprzężenia dla A i B oraz warunku sprzężenia dla B i C. Składnię sprzężenia zewnętrznego można znaleźć w sekcji SELECT.

Zrobiono z http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/queries006.htm


4

Widziałem pewne sprzeczności w powyższych odpowiedziach, właśnie wypróbowałem następujące na Oracle 12c i poniższe są poprawne:

LEWE POŁĄCZENIE ZEWNĘTRZNE

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

PRAWE POŁĄCZENIE ZEWNĘTRZNE

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

0

LEWE POŁĄCZENIE ZEWNĘTRZNE

WYBIERZ * Z A, B GDZIE A. kolumna = B. kolumna (+)

PRAWE POŁĄCZENIE ZEWNĘTRZNE

WYBIERZ * Z A, B GDZIE A. kolumna (+) = B. kolumna


-2

W tym wątku są nieprawidłowe informacje. Skopiowałem i wkleiłem nieprawidłowe informacje:

LEWE POŁĄCZENIE ZEWNĘTRZNE

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

PRAWE POŁĄCZENIE ZEWNĘTRZNE

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

Powyższe jest NIEPRAWIDŁOWE !!!!! To jest odwrócone. Sposób, w jaki ustaliłem, że jest nieprawidłowy, pochodzi z następującej książki:

Oracle OCP Wprowadzenie do Oracle 9i: Przewodnik po egzaminach SQL . Page 115 Tabela 3-1 zawiera dobre podsumowanie na ten temat. Nie mogłem zrozumieć, dlaczego mój przekonwertowany SQL nie działa poprawnie, dopóki nie poszedłem do starej szkoły i nie spojrzałem na drukowaną książkę!

Oto podsumowanie tej książki, skopiowane wiersz po wierszu:

Składnia sprzężenia zewnętrznego Oracle:

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

Odpowiednik ANSI / ISO:

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

Zauważ tutaj, że jest to odwrotność tego, co napisano powyżej. Przypuszczam, że ta książka może mieć erratę, jednak ufam tej książce bardziej niż temu, co jest w tym wątku. To przewodnik po egzaminach na głośny płacz ...


4
Jest to sprzeczne z tym, do czego dołączyłem w mojej odpowiedzi, czyli fragmentem z Oracle Database 10g SQL (Osborne ORACLE Press Series), wydanie 1 (20 lutego 2004), stwierdzając: „W lewym złączeniu zewnętrznym operator sprzężenia zewnętrznego jest aktualnie włączony prawo operatora równości ”. Oto demo twojego przykładu . Wyniki a.col_1(+) = b.col_1dopasowania RIGHT JOIN, a nie LEFT JOIN.
Wiseguy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.