Условия в LEFT JOIN (ВСТУПЛЕНИЕ ВМЕСТЕ) против INNER JOIN

SELECT A.COL1, B.COL1,C.COL1
FROM TABLEA A
LEFT JOIN TABLEB B ON A.COL1 = B.COL1
LEFT JOIN TABLEC C ON (
        C.COL3 IS NOT NULL
        AND (
              C.COL2 = 664
              AND A.COL1 = C.COL1
        )
)

Что касается технических требований SQL, что означает условие, записанное в круглых скобках после LEFT JOIN TABLE C ON? Почему это необходимо?

Ответ 1

Внутреннее соединение (JOIN или INNER JOIN, CROSS JOIN или запятая) сначала выполняет CROSS JOIN. (Т. Е. Возвращает все строки, которые могут быть сделаны путем добавления строки из ее левой таблицы и строки из ее правой таблицы.) Затем любое ON удаляет строки, которые не соответствуют его условиям. OUTER JOIN возвращает строки соответствующего INNER JOIN plus, для левой таблицы (LEFT) или правой таблицы (RIGHT) или обеих таблиц (FULL), любые непревзойденные строки, расширенные с помощью NULL. После FROM WHERE удаляет строки, которые не соответствуют его условиям.

Если условие находится в ON, то соответствующие сопоставления удаляются в FROM. Но если это условие вместо этого в WHERE, то соответствующие строки и любые строки, содержащие их через последующие соединения, все равно удаляются. Поэтому, если у FROM только внутренние соединения, то не имеет значения, находится ли условие в ON или WHERE.

Но если FROM имеет OUTER JOIN ON условия, то перекрестные строки объединения, не удовлетворяющие условию, удаляются, и добавляются некоторые расширенные строки с NULL, тогда как перемещение этого условия в WHERE делает удаление, но не добавление.

Не нужно, чтобы язык имел ON для INNER JOIN, так как вместо t1 INNER JOIN t2 ON condition вместо него можно было использовать (SELECT * FROM t1 INNER JOIN t2 WHERE condition).

Из вышесказанного вы можете выработать следующее: для последовательности INNER JOINS после любого последнего ВНЕШНЕГО СОЕДИНЕНИЯ (в том числе, когда нет OUTER JOIN), можно свободно перемещать условия между их ON и WHERE. Но не для ON или до последнего ВНЕШНЕГО СОЕДИНЕНИЯ, потому что они могут влиять на его входы и влияют на вывод строк NULLed. Там просто нет причин ожидать того же результата, если такое условие было перенесено из ON в WHERE.

Для вашего кода: Вероятно, запрос предназначен для возврата A.COL1 в качестве идентификатора с ассоциированными данными A, B и C с теми, у которых нет информации B, тем не менее включенной (с B и C info NULLed) и теми которые делают, но не имеют C-информации или делают, но не имеют не-NULL C.COL3 или имеют, но не имеют C.COL2 = 664, тем не менее, включены (с C-информацией NULLed).

Ответ 2

Более ранние версии ANSI SQL не содержали предложение ON для условий соединения - он использовал предложение where для всего. Это было хорошо для внутренних объединений, но поскольку приложения баз данных начали использовать внешние соединения, возникли проблемы, возникшие при таком подходе. Некоторые из вас могут помнить оригинальный синтаксис эры ANSI-89 для *= и =*. Они использовались в предикатах для определения поведения внешнего соединения. В этом случае хорошо сохраняйте несогласованные строки из A в дополнение к нормальным строкам, возвращаемым из соединения:

SELECT A.COL1, B.COL1,C.COL1
FROM TABLEA A
LEFT JOIN TABLEB B ON A.COL1 = B.COL1
LEFT JOIN TABLEC C ON (
        C.COL3 IS NOT NULL
        AND (
              C.COL2 = 664
              AND A.COL1 = C.COL1
        )
)

Это очень полезно, когда вы пытаетесь выяснить, что должно произойти в запросе. Он помогает семантически определять набор строк, которые должны возвращаться из соединения.

Предложение ON: этот синтаксис позволяет указать имена столбцов для ключей соединения в обеих таблицах Предложение ON используется для объединения таблиц, в которых имена столбцов не совпадают в обеих таблицах. Условия соединения удаляются из условий фильтра в предложении WHERE.

Ответ 3

С OUTER JOIN ваш C может быть NULL, потому что нет соответствия для A.COL1.

Если это случай, то никогда не может быть C.COL2 = 664, что означает, что любой оператор WHERE отбрасывает строку.

Поместив условие в предложение ON, вы просите применить его к условию JOIN, а не как фильтр для результата.

Для не внешних соединений это не имеет значения.