В Oracle меня учили присоединяться как
select *
from Table_a a, Table_b b, Table_c c
where a.id = b. Id and b.thing = c.thing
Я использовал этот метод, игнорируя обучение, которое я прошел, чтобы делать явные соединения, поскольку все в моей компании используют описанный выше подход.
Мы перешли на SQL-сервер (студия данных Azure), и я использую
select *
from Table_a a
join Table_b b on a.id = b.id
join Table_c c on b.thing = c.thing
Для внутренних соединений я получаю это.
Когда я меняю это на левое соединение, вот так
select *
from Table_a a
left join Table_b b on a.id = b.id
left join Table_c c on b.thing = c.thing
Я понимаю, что такое левое соединение, но не могу понять, как оно работает.
Я говорю это - использовать все записи из a, а затем возвращать все значения из таблицы b с нулями, когда ничего не найдено?
Бит, с которым я борюсь, - это соединение с c.
Использую ли я таблицу a в качестве основы, поэтому ищу все значения из a, а затем все значения, совпадающие с c, как нули?
Что произойдет, если a и b было внутренним соединением, а c — левым?
Осталось ли c присоединиться к b?
Или оставил присоединение к себе?
Пример:
select *
from Table_a a
join Table_b b on a.id = b.id
left join Table_c c on b.thing = c.thing
Говорю ли я в этом сценарии, что хочу, чтобы левое соединение было только с b, поэтому я ищу записи только в a, все в b и сопоставляю значения с нулями в c?
Я понимаю, что произойдет, если я использую ВСЕ левые соединения, но если они смешаны и сопоставлены, я не могу уяснить это?
Задайте 1 конкретный исследовательский неповторяющийся вопрос о первом месте, где вы застряли. Не куча вопросов о куче проблем с кодом. Вопросы отладки требуют минимально воспроизводимого примера . Как задать вопрос Справочный центр В чем разница между «INNER JOIN» и «OUTER JOIN»? ) Сколько исследовательских усилий ожидается от пользователей Stack Overflow? «Я понимаю, что такое левое соединение» Очевидно, что нет. Почему ты это пишешь? (Риторический.)
Для вопросов по отладке требуется минимальный воспроизводимый пример — вырезать, вставлять и запускать код, включая инициализацию; желаемый и фактический результат (включая дословные сообщения об ошибках); теги и версии; четкая спецификация и объяснение. Для SQL включите DDL и табличный код инициализации. Для отладки, которая включает в себя наименьшее количество кода, которое вы можете предоставить, это код, который вы показываете, в порядке, расширенный кодом, который вы показываете, что это не в порядке. Как задать вопрос Справочный центр Когда вы получаете результат, которого не ожидали, приостановите достижение общей цели, перейдите к первому подвыражению с неожиданным результатом и скажите, чего вы ожидали и почему, обосновав это документацией. (Основы отладки.)
«В Oracle меня учили присоединяться, поскольку» Меня снова сбивают с толку люди из Oracle, они все еще думают, что сейчас 1980-е? Мы переехали в 1992 год, а сейчас 2024 год... Честно говоря, эти же люди просят вас говорить на латыни, полагая, что это не мертвый язык?
Вероятно, проще всего просто попробовать все это и увидеть результаты:
CREATE TABLE a (id int, col1 varchar(10));
CREATE TABLE b (id int, col1 varchar(10));
CREATE TABLE c (id int, col1 varchar(10));
INSERT INTO a (id, col1) VALUES (1, 'a1'), (2, 'a2'),(3, 'a3');
INSERT INTO b (id, col1) VALUES (1, 'b1'), (2, 'b2'),(4, 'b4');
INSERT INTO c (id, col1) VALUES (1, 'c1'), (3, 'c3'),(4, 'c4');
SELECT *
FROM a
LEFT OUTER JOIN b
ON a.id = b.id
LEFT OUTER JOIN c
ON b.id = c.id;
+----+------+------+------+------+------+
| id | col1 | id | col1 | id | col1 |
+----+------+------+------+------+------+
| 1 | a1 | 1 | b1 | 1 | c1 |
| 2 | a2 | 2 | b2 | null | null |
| 3 | a3 | null | null | null | null |
+----+------+------+------+------+------+
В этом запросе со всеми LEFT OUTER JOIN
выбираются все записи из a
, а затем только соответствующие записи в b
и, наконец, только записи из c
, которые соответствуют записям b
, пережившим предыдущее объединение, прошли.
SELECT *
FROM a
INNER JOIN b
ON a.id = b.id
LEFT OUTER JOIN c
ON b.id = c.id;
+----+------+----+------+------+------+
| id | col1 | id | col1 | id | col1 |
+----+------+----+------+------+------+
| 1 | a1 | 1 | b1 | 1 | c1 |
| 2 | a2 | 2 | b2 | null | null |
+----+------+----+------+------+------+
Переключение первого соединения на INNER JOIN
приводит к изменению вывода. Теперь записи ДОЛЖНЫ совпадать между a
и b
, чтобы пережить ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Тогда только те записи в c
, которые совпадают между тем, что осталось от b
, будут иметь свои значения.
Вы можете увидеть это в действии здесь: https://dbfiddle.uk/3pB_Rb_3
Подумайте о соединениях шаг за шагом: после первого соединения вы получаете некоторую промежуточную таблицу, а затем присоединяетесь к третьей таблице C в этой таблице.
Ваш ответ можно улучшить, добавив дополнительную вспомогательную информацию. Пожалуйста, отредактируйте , добавив дополнительную информацию, например цитаты или документацию, чтобы другие могли подтвердить правильность вашего ответа. Более подробную информацию о том, как писать хорошие ответы, вы можете найти в справочном центре.
Здесь полезно вспомнить вашу формальную реляционную алгебру, где то, что мы считаем таблицей, является одним из способов выразить то, что формально называется отношением.
В этом контексте результатом соединения двух отношений (A и B) является другое отношение.
Бит, с которым я борюсь, - это соединение с c. Использую ли я таблицу a в качестве основы, поэтому ищу все значения из a, а затем все значения, совпадающие с c, как нули?
Нет. Вы можете думать об этом как о соединении C с результатом соединения A + B. В конце концов, соединение A с B — это всего лишь еще одно отношение.
В действительности все может пойти не так. База данных будет использовать ярлыки там, где это возможно, чтобы повысить эффективность и производительность. Вы даже можете бесплатно изменить порядок ваших JOIN при фактическом выполнении запроса, если считаете, что новый порядок по-прежнему точен и будет работать лучше. Но семантически вы можете думать об этом так, как будто операции соединения выполняются сверху вниз или слева направо, в зависимости от того, как вы форматируете запрос.
... да, и, конечно же, в соответствии с тем, как вы строите круглые скобки или вложение. Если вы думаете, что A join B on .. left join C on ...
сбивает с толку, подождите, пока не увидите такие вещи, как A JOIN (B JOIN C ON ...) ON ...
(которого, кстати, обычно следует избегать, но оно совершенно законно и даже время от времени полезно).
Это не имеет никакого отношения к Oracle. Впервые показанный синтаксис использовался в 1980-х и начале 1990-х годов. Так что либо вы тогда начали с Oracle, либо у вас плохой учитель.
Что касается левых внешних соединений: после того, как вы внешне присоединитесь к таблице, а затем присоедините другую таблицу к внешней таблице, вы также должны выполнить внешнее соединение.
Например:
select *
from a
left join b on b.col_1 = a.col_2
left join c on c.col_3 = b.col_4;
Вы выбираете строку A. Вы ищете совпадающие строки B. Если совпадений нет, вы получаете фиктивную строку B с ее столбцами col_1 и col_4, установленными в NULL, как вы описываете. Теперь вы ищете совпадающие строки C, но c.col_3 = b.col_4
никогда не может быть правдой, потому что col_4 имеет значение NULL. При внешнем соединении совпадений нет, поэтому мы получаем фиктивную строку C со столбцами, установленными в NULL. Все отлично, как хотелось.
Если бы вместо этого у нас было внутреннее соединение:
select *
from a
left join b on b.col_1 = a.col_2
inner join c on c.col_3 = b.col_4;
мы бы выполнили внешнее соединение B, но поскольку внешняя объединенная фиктивная строка не имеет совпадения в C, внешняя объединенная строка будет отклонена, и в итоге вы получите простое
select *
from a
inner join b on b.col_1 = a.col_2
inner join c on c.col_3 = b.col_4;
результат.
Кстати, то же самое происходит, если вы выполняете внешнее соединение, но затем требуете определенных значений в предложенииwhere:
select *
from a
left join b on b.col_1 = a.col_2
where b.col_3 = 123;
превращает внешнее соединение в простое внутреннее соединение, так как в строке, соединенной с внешним соединением, столбец col_3 имеет значение null и, следовательно, отклоняется в предложенииwhere.
«Путь Oracle» был неправильным даже в Oracle. Oracle поддерживает новый подход вот уже 25 лет.