Зліва Зовнішнє Приєднання за допомогою + входу в систему Oracle 11g


81

Хто-небудь може сказати мені, чи є нижче 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

Відобразіть усі деталі незалежно від того, постачальник їх постачає чи ні:

ВИБЕРІТЬ P.Part_Id, S.Supplier_Name
ВІД частини P, постачальник S
ДЕ P.Supplier_Id = S.Supplier_Id (+)

ВИБЕРІТЬ P.Part_Id, S.Supplier_Name
ВІД частини P, постачальник S
ДЕ 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 clause OUTER JOIN синтаксис ... "
Sylvain Leroux

Вибачте і за застарілу відповідь :), але те, що говорить Oracle і як його статистика працює для оптимізації запитів, - це дві різні речі, і, можливо, Oracle змінив свою позицію, а також досягнення своїх внутрішніх оптимізаторів
міф

Відповіді:


188

TableA LEFT OUTER JOIN TableBеквівалентно TableB RIGHT OUTER JOIN Table A.

В Oracle (+)позначає "необов'язкову" таблицю в JOIN. Отже, у вашому першому запиті це a 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 - це неявні JOINs та явні JOINs . Це різні стилі написання JOIN, але вони функціонально еквівалентні.

Дивіться це питання SO .

Неявні ПРИЄДНАННЯ просто перелічують усі таблиці разом. Умови об'єднання вказані в реченні WHERE.

Неявне ПРИЄДНАННЯ

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

Явні JOINs пов'язують умови приєднання з включенням конкретної таблиці, а не в речення WHERE.

Явне JOIN

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

Ці неявні ПРИЄДНАННЯ може бути важче прочитати та зрозуміти, і вони також мають кілька обмежень, оскільки умови приєднання змішані в інших умовах ДЕ. Таким чином, неявні JOIN, як правило, рекомендуються проти явного синтаксису.


3
Правильно, я зрозумів зараз - JOIN створюється неявно за наявності (+). Класно.
Kerrek SB

2
@Mike: Так працює синтаксис +. Це означає "необов’язково", тому читайте це як "Перерахуйте всі деталі, за бажанням зрівняйте постачальника".
Kerrek SB

2
@Mike: Поки ти знаєш, що ти вибираєш, насправді не має значення, як ти це називаєш. Але зробіть собі послугу і JOINзамість цього використовуйте ідіоматичний синтаксис! Тоді немає місця плутанині.
Kerrek SB

1
@TomJMuthirenthi Без використання явного FULL OUTER JOINсинтаксису вам знадобиться UNION [ALL]два набори результатів разом: один для A = B (+) і один для B = A (+). Приклад у цьому питанні .
Wiseguy

1
Значок "(+)" надходить у стовпці таблиці, що генерує підрядки нулів.
philipxy

9

Ці два запити виконуються OUTER JOIN. Дивись нижче

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

  • Ви не можете вказати оператор (+) у блоці запиту, який також містить синтаксис приєднання речення 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


4

Я побачив деякі суперечності у відповідях вище, я просто спробував наступне на Oracle 12c, і наступне є правильним:

ЛІВО ВНЕШНЄ ПРИЄДНАННЯ

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

ПРАВИЛЬНО ВНЕШНЄ ПРИЄДНАННЯ

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

0

ЛІВО ВНЕШНЄ ПРИЄДНАННЯ

ВИБЕРІТЬ * ВІД A, B ДЕ A.column = B.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 . Сторінка 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 Database 10g SQL (Osborne ORACLE Press Series), 1-е видання (20 лютого 2004 р.), Де сказано: "У лівому зовнішньому об’єднанні оператор зовнішнього об’єднання фактично право оператора рівності ". Ось демонстрація вашого прикладу . Результати a.col_1(+) = b.col_1матчу ПРАВИЛЬНЕ ПРИЄДНАННЯ, а НЕ ЛІВО.
Wiseguy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.