Смешивание внутренних и внешних объединений 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 не совпадают.

Другие вопросы по тегам