Смешивание внутренних и внешних объединений SQL
У меня есть следующий устаревший запрос Oracle SQL, с которым я работаю:
SELECT *
FROM
table1, table2, table3, table4
WHERE
table1.job= table2.job(+)
AND table1.event = table3.event(+)
AND
((table2.column1= table4.key AND table4.resource_type = 'xxx')
OR (table2.column2 = table4.key AND table4.resource_type = 'yyy'))
Я вижу, что таблица имеет левое внешнее соединение на table2, а таблица 1 имеет левое внешнее соединение на table3. Но что теперь делает последний пункт?
Когда я смотрю на диаграмму Венна, я думаю, что она возвращает всю таблицу1 плюс записи, которые имеют общие таблицы2 и таблицы4. Так выполняет ли этот запрос своего рода объединение двух наборов данных?
3 ответа
LEFT JOIN
в table2
действительно INNER JOIN
, WHERE
пункт отменяет внешнее соединение. Поэтому я думаю, что это эквивалентный запрос:
SELECT *
FROM table1 JOIN
table2
ON table1.job = table2.job JOIN
table4
ON (table2.column1 = table4.key AND table4.resource_type = 'xxx') OR
(table2.column2 = table4.key AND table4.resource_type = 'yyy') LEFT JOIN
table3
ON table1.event = table3.event;
Просто чтобы прояснить вопрос о превращении внешнего соединения во внутреннее соединение:
Если предложение WHERE содержит условие, которое сравнивает столбец из таблицы B с константой, то к столбцу должен применяться оператор (+), чтобы Oracle возвращал строки из таблицы A, для которых он сгенерировал пустые значения для этого столбца. В противном случае Oracle возвращает только результаты простого объединения.
В таблице 4 есть записи (как минимум) двух типов ресурсов { 'xxx', 'yyy' }. Таблица 2 имеет соответствующие идентификаторы для типа ресурса "xxx" в столбце 1 и для типа ресурса "yyy" в столбце 2.
Последний пункт, т.е. ((table2.column1= table4.key AND table4.resource_type = 'xxx') OR (table2.column2 = table4.key AND table4.resource_type = 'yyy'))
на самом деле включает "левое соединение" table2
в соединение, а точнее в нечто вроде table1 join table2 join table4
так, что запрос не обязательно будет содержать все записи table1
,
Вы можете думать об этом следующим образом: Предположим, table1
а также table2
фактически оставлены соединенными, так что (промежуточный) результат содержит все кортежи из table1
в сочетании с атрибутами table2
где table1.job
а также table2.job
совпадают, и с нулевыми значениями для table2
-признаки где job
не совпадает. Затем where
условие table2.column1= table4.key
удалит все записи из (промежуточного) результата, где table2.column1
не соответствует ни одной записи в table4
; обратите внимание, что null
-значение в table2.column1
результат левого объединения никогда не совпадет и позволит отфильтровать эти записи. Следовательно, у вас не будет никаких записей в результате, где table1.job
а также table2.job
не совпадают.