Оставлены ли внешние объединения ассоциативными?
Легко понять, почему оставшиеся внешние объединения не являются коммутативными, но у меня возникают проблемы с пониманием того, являются ли они ассоциативными. Несколько онлайн-источников предполагают, что это не так, но мне не удалось убедить себя, что это так.
Предположим, что у нас есть три таблицы: A, B и C.
Пусть A содержит два столбца, идентификатор и B_ID, где ID - первичный ключ таблицы A, а B_ID - это внешний ключ, соответствующий первичному ключу таблицы B.
Пусть B содержит два столбца, идентификатор и C_ID, где ID - первичный ключ таблицы B, а C_ID - это внешний ключ, соответствующий первичному ключу таблицы C.
Пусть C содержит два столбца, идентификатор и VALUE, где ID является первичным ключом таблицы C, а значение VALUE содержит только некоторые значения.
Тогда не должно (A left outer join B) left outer join C
быть равно A left outer join (B left outer join C)
?
Ответы
Ответ 1
Если вы предполагаете, что вы ПРИСОЕДИНЯЕТЕСЬ к внешнему ключу, как, по-видимому, подразумевает ваш вопрос, то да, я думаю, что OUTER JOIN гарантированно будет ассоциативным, как указано в ответе Пшемыслава Крюглея.
Однако, учитывая, что вы на самом деле не указали условие JOIN, педантически правильный ответ таков: нет, они не гарантируют ассоциативность. Есть два простых способа нарушить ассоциативность с помощью извращенных предложений ON
.
1. Одно из условий JOIN включает столбцы из всех трех таблиц.
Это довольно дешевый способ нарушить ассоциативность, но, строго говоря, ничего в вашем вопросе не запрещает это. Используя имена столбцов, предложенные в вашем вопросе, рассмотрите следующие два запроса:
-- This is legal
SELECT * FROM (A JOIN B ON A.b_id = B.id)
JOIN C ON (A.id = B.id) AND (B.id = C.id)
-- This is not legal
SELECT * FROM A
JOIN (B JOIN C ON (A.id = B.id) AND (B.id = C.id))
ON A.b_id = B.id
Нижний запрос даже не является допустимым, но верхний. Очевидно, это нарушает ассоциативность.
2. Одно из условий JOIN может быть выполнено, несмотря на то, что все поля одной таблицы равны NULL
Таким образом, мы можем даже иметь разное количество строк в нашем наборе результатов в зависимости от порядка соединений. Например, пусть условием СОЕДИНЕНИЯ А на В является A.b_id = B.id
, а условием СОЕДИНЕНИЯ В на С является B.id IS NULL
.
Таким образом, мы получаем эти два запроса с очень разным выводом:
SELECT * FROM (A LEFT OUTER JOIN B ON A.b_id = B.id)
LEFT OUTER JOIN C ON B.id IS NULL;
SELECT * FROM A
LEFT OUTER JOIN (B LEFT OUTER JOIN C ON B.id IS NULL)
ON A.b_id = B.id;
Вы можете увидеть это в действии здесь: http://sqlfiddle.com/#!9/d59139/1
Ответ 2
В этой теме говорится, что они не ассоциативны: ассоциативно ли левое соединение?
Тем не менее, я нашел в Интернете какую-то книгу, в которой говорится, что ВНЕШНИЕ СОЕДИНЕНИЯ ассоциативны, когда таблицы в левой и крайней правой частях не имеют общих атрибутов (здесь).
Вот графическое представление (MSPaint ftw):
Еще один способ взглянуть на это:
Поскольку вы сказали, что таблица A соединяется с B, а B соединяется с C, то:
- Когда вы впервые соединяете A и B, у вас остаются все записи из A. Некоторые из них имеют значения из B. Теперь, для некоторых из тех строк, для которых вы получили значение из B, вы получаете значения из C.
- Когда вы впервые соединяете B и C, вы и вся таблица B, где некоторые записи имеют значения из C. Теперь вы берете все записи из A и объединяете некоторые из них со всеми строками из B, соединенными с C. Здесь опять же, вы получаете все строки из A, но некоторые из них имеют значения из B, некоторые из которых имеют значения из C.
Я не вижу никакой возможности, чтобы в описанных вами условиях произошла потеря данных в зависимости от последовательности LEFT-соединений.
Основываясь на данных, предоставленных Тилаком в его ответе (который теперь удален), я построил простой тестовый пример:
CREATE TABLE atab (id NUMBER, val VARCHAR2(10));
CREATE TABLE btab (id NUMBER, val VARCHAR2(10));
CREATE TABLE ctab (id NUMBER, val VARCHAR2(10));
INSERT INTO atab VALUES (1, 'A1');
INSERT INTO atab VALUES (2, 'A2');
INSERT INTO atab VALUES (3, 'A3');
INSERT INTO btab VALUES (1, 'B1');
INSERT INTO btab VALUES (2, 'B2');
INSERT INTO btab VALUES (4, 'B4');
INSERT INTO ctab VALUES (1, 'C1');
INSERT INTO ctab VALUES (3, 'C3');
INSERT INTO ctab VALUES (5, 'C5');
SELECT ab.aid, ab.aval, ab.bval, c.val AS cval
FROM (
SELECT a.id AS aid, a.val AS aval, b.id AS bid, b.val AS bval
FROM atab a LEFT OUTER JOIN btab b ON (a.id = b.id)
) ab
LEFT OUTER JOIN ctab c ON (ab.bid = c.id)
ORDER BY ab.aid
;
AID AVAL BVAL CVAL
---------- ---------- ---------- ----------
1 A1 B1 C1
2 A2 B2
3 A3
SELECT a.id, a.val AS aval, bc.bval, bc.cval
FROM
atab a
LEFT OUTER JOIN (
SELECT b.id AS bid, b.val AS bval, c.id AS cid, c.val AS cval
FROM btab b LEFT OUTER JOIN ctab c ON (b.id = c.id)
) bc
ON (a.id = bc.bid)
ORDER BY a.id
;
ID AVAL BVAL CVAL
---------- ---------- ---------- ----------
1 A1 B1 C1
2 A2 B2
3 A3
В этом конкретном примере кажется, что оба решения дают одинаковый результат. Я не могу представить ни одного другого набора данных, который бы заставлял эти запросы возвращать разные результаты.
Проверьте в SQLFiddle:
Ответ 3
В дополнение к предыдущим ответам: тема хорошо обсуждается в Michael M. David, Advanced ANSI SQL Data Modeling and Structure Processing, Artech House, 1999, стр. 19-21. Доступные страницы онлайн.
Я считаю особенно примечательным, что он обсуждает, что таблица (LEFT JOIN...) и предложения присоединения (ON...) должны рассматриваться отдельно, поэтому ассоциативность может относиться к обоим (переустановка табличных предложений и re - установление условий соединения, т.е. по статьям). Таким образом, понятие ассоциативности не совпадает с понятием ассоциативности, например, с добавлением чисел, оно имеет два измерения.