Разъяснение по поводу объединений

В 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?

Я понимаю, что произойдет, если я использую ВСЕ левые соединения, но если они смешаны и сопоставлены, я не могу уяснить это?

«Путь Oracle» был неправильным даже в Oracle. Oracle поддерживает новый подход вот уже 25 лет.

Joel Coehoorn 27.06.2024 22:21

Задайте 1 конкретный исследовательский неповторяющийся вопрос о первом месте, где вы застряли. Не куча вопросов о куче проблем с кодом. Вопросы отладки требуют минимально воспроизводимого примера . Как задать вопрос Справочный центр В чем разница между «INNER JOIN» и «OUTER JOIN»? ) Сколько исследовательских усилий ожидается от пользователей Stack Overflow? «Я понимаю, что такое левое соединение» Очевидно, что нет. Почему ты это пишешь? (Риторический.)

philipxy 27.06.2024 23:42

«В Oracle меня учили присоединяться, поскольку» Меня снова сбивают с толку люди из Oracle, они все еще думают, что сейчас 1980-е? Мы переехали в 1992 год, а сейчас 2024 год... Честно говоря, эти же люди просят вас говорить на латыни, полагая, что это не мертвый язык?

Thom A 28.06.2024 00:09
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
4
83
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вероятно, проще всего просто попробовать все это и увидеть результаты:

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.

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