В чем разница между использованием оракула плюс обозначение (+)
над стандартной записью ansi join
?
Есть ли разница в производительности?
Является ли обозначение "плюс" устаревшим?
AFAIK, нотация (+)
присутствует только для обратной совместимости, потому что Oracle дебютировала перед тем, как был установлен стандарт ANSI для объединений. Это специфично для Oracle, и вам следует избегать использования его в новом коде, если имеется эквивалентная версия, совместимая со стандартами.
Изменить: Кажется, что существуют различия между ними, а нотация (+)
имеет ограничения, которые не имеют синтаксиса ANSI join. Сам Oracle рекомендует не использовать нотацию (+)
.
Полное описание здесь, в Справочник по языку базы данных Oracle Database
11g Выпуск 1 (11.1):
Oracle рекомендует использовать синтаксис FROM
OUTER JOIN
, а не оператор объединения Oracle. Запросы внешнего соединения, использующие оператор объединения Oracle (+)
, подчиняются следующим правилам и ограничениям, которые не применяются к синтаксису FROM
OUTER JOIN
:
(+)
в блоке запроса, который также содержит синтаксис соединения предложения FROM
.(+)
может отображаться только в предложении WHERE
или в контексте левой корреляции (при указании предложения TABLE
) в предложении FROM
и может применяться только к столбцу таблицы или вида.Если A и B соединены несколькими условиями соединения, вы должны использовать оператор (+)
во всех этих условиях. Если вы этого не сделаете, тогда Oracle Database вернет только строки, полученные в результате простого соединения, но без предупреждения или ошибки, чтобы сообщить вам, что у вас нет результатов внешнего соединения.
Оператор (+)
не создает внешнее соединение, если вы укажете одну таблицу во внешнем запросе и другую таблицу во внутреннем запросе.
Вы не можете использовать оператор (+)
для внешнего соединения таблицы для себя, хотя самосоединения действительны.
Например, следующий оператор недействителен:
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;
Оператор (+)
может применяться только к столбцу, а не к произвольному выражению. Однако произвольное выражение может содержать один или несколько столбцов, помеченных оператором (+)
.
A WHERE
условие, содержащее оператор (+)
, нельзя комбинировать с другим условием, используя логический оператор OR
.
A WHERE
не может использовать условие сравнения IN
для сравнения столбца, помеченного оператором (+)
, с выражением.
Если предложение WHERE
содержит условие, которое сравнивает столбец из таблицы B с константой, тогда оператор (+)
должен быть применен к столбцу, чтобы Oracle возвращал строки из таблицы A, для которых он сгенерировал null для этой колонки. В противном случае Oracle возвращает только результаты простого соединения.
В запросе, который выполняет внешние соединения более двух пар таблиц, одна таблица может быть таблицей с нулевым значением только для одной другой таблицы. По этой причине вы не можете применить оператор (+)
к столбцам B в условии соединения для A и B и условия соединения для B и C. Обратитесь к SELECT
для синтаксиса внешнего соединения.
Я согласен с ответом Тони Миллера и хотел бы добавить, что есть также несколько вещей, которые вы НЕ можете делать с (+) синтаксисом:
b.id = a.id (+) AND c.id = a.id (+)
не является приемлемым предложением)a.b_id = b.id (+) AND b.c_id = c.id (+)
Я унаследовал нечто подобное, и я a.b_id = b.id (+) AND b.c_id = c.id (+)
вопросом, что действительно возвращается, если происходит соединение a
b
до нуля
A -> B -> C
Применяются те же правила, что и для стандартных объединений ANSI: цепочка внешних объединений разрывается, если одно из ее звеньев является регулярным соединением. Другими словами, A LEFT JOIN B INNER JOIN C
эквивалентно A JOIN B JOIN C
Обозначения по-прежнему поддерживаются по версии Oracle 10 (и я считаю, что 11). Это использование считается "старомодным", а также не является портативной базой данных, как синтаксис ANSI JOIN. Он также считается гораздо менее читаемым, хотя, если вы исходите из фона +, привыкающего к ANSI JOIN, может занять немного времени. Важная вещь, которую нужно знать перед тем, как бросить кирпич в Oracle, заключается в том, что они разработали свой синтаксис + до того, как комитет ANSI завершил определения для объединений.
Нет разницы в производительности; они выражают одно и то же.
Изменить: "Не переносимым" я должен был сказать "поддерживается только в Oracle SQL"
MATERIALIZED VIEW
с FAST REFRESH
вы не можете использовать синтаксис ANSI. Я только что проверил страницу Oracle для этой проблемы, она все еще присутствует. Oracle не считает это ошибкой! Подробности смотрите в Oracle Doc ID 1372720.1, если у вас есть доступ к поддержке Oracle.
Наиболее полным ответом, очевидно, является nagul.
Добавление для тех, кто ищет быстрый перевод/сопоставление с синтаксисом ANSI:
--
-- INNER JOIN
--
SELECT *
FROM EMP e
INNER JOIN DEPT d ON d.DEPTNO = e.DEPTNO;
-- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
DEPT d
WHERE d.DEPTNO = e.DEPTNO;
--
-- LEFT OUTER JOIN
--
SELECT *
FROM EMP e
LEFT JOIN DEPT d ON d.DEPTNO = e.DEPTNO;
-- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
DEPT d
WHERE d.DEPTNO (+) = e.DEPTNO;
--
-- RIGHT OUTER JOIN
--
SELECT *
FROM EMP e
RIGHT JOIN DEPT d ON d.DEPTNO = e.DEPTNO;
-- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
DEPT d
WHERE d.DEPTNO = e.DEPTNO(+);
--
-- CROSS JOIN
--
SELECT *
FROM EMP e
CROSS JOIN DEPT d;
-- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
DEPT d;
--
-- FULL JOIN
--
SELECT *
FROM EMP e
FULL JOIN DEPT d ON d.DEPTNO = e.DEPTNO;
-- Synonym in deprecated oracle (+) syntax !NOT WORKING!
SELECT *
FROM EMP e,
DEPT d
WHERE d.DEPTNO (+) = e.DEPTNO(+);
Одна из веских причин использовать синтаксис ANSI для старого синтаксиса синтаксиса Oracle заключается в том, что существует вероятность непредвиденного создания декартова продукта. С большим количеством таблиц есть шанс пропустить соединение неявное со старым синтаксисом объединения Oracle, однако с синтаксисом ANSI вы не можете пропустить какое-либо соединение, поскольку вы должны явно указывать их.
Разница между сильным синтаксисом внешнего синтаксиса Oracle и синтаксисом ANSI/ISO.
LEFT OUTER JOIN -
SELECT e.last_name,
d.department_name
FROM employees e,
departments d
WHERE e.department_id = d.department_id(+);
SELECT e.last_name,
d.department_name
FROM employees e
LEFT OUTER JOIN departments d
ON (e.department_id = d.department_id);
ПРАВИЛЬНАЯ ВСТРОЕННАЯ РАБОТА -
SELECT e.last_name,
d.department_name
FROM employees e,
departments d
WHERE e.department_id(+) = d.department_id;
SELECT e.last_name,
d.department_name
FROM employees e
RIGHT OUTER JOIN departments d
ON (e.department_id = d.department_id);
ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ -
До того, как встроенная поддержка хэш-функции полностью нарушена в 11gR1, Oracle внутренне преобразует FULL OUTER JOIN следующим образом -
SELECT e.last_name,
d.department_name
FROM employees e,
departments d
WHERE e.department_id = d.department_id(+)
UNION ALL
SELECT NULL,
d.department_name
FROM departments d
WHERE NOT EXISTS
(SELECT 1 FROM employees e WHERE e.department_id = d.department_id
);
SELECT e.last_name,
d.department_name
FROM employees e
FULL OUTER JOIN departments d
ON (e.department_id = d.department_id);
Посмотрите это.
Я использую (+) нотацию, потому что на этом основаны почти все запросы Oracle, связанные с r12. Я не видел ни одного SQL-запроса со стандартным выражением "join" в запросах Oracle APPS (даже тех, которые предоставлены самим Oracle). Если вы мне не верите, просто перейдите по любой информации, связанной с приложениями Oracle. Например: Запросы, связанные с основными средствами
Обозначение Oracle (+) используется только в Oracle, специально для поставщика. И ANSI, стандартная запись регистрации может быть использована в любой СУБД (например, Sql Server, MySql и т.д.). В противном случае нет разницы между нотами Oracle (+) и стандартными нотами объединения ANSI.
Если вы используете стандартную запись регистрации ANSI в своем Sql Query, вы можете использовать тот же запрос в любой СУБД. И, если вы портируете вашу базу данных от Oracle к любой другой RDBMS в этом состоянии вам нужно использовать синтаксис ANSI.