Решён
Как соединить две таблицы в MySQL - JOIN не дает нужный результат

Застрял на простой (казалось бы) задаче. Есть две таблицы:

users (id, name, city_id)
cities (id, city_name)

Хочу получить список всех пользователей с названием их города. Пробовал INNER JOIN - не показывает пользователей у которых city_id = NULL. Попробовал просто перечислить таблицы через запятую - получил декартово произведение.

MySQL 8.0, локальная база для учебного проекта. Что делаю не так и какой JOIN нужен в моем случае?

Решение
87
Эксперт • 1 ответ

LEFT JOIN вместо INNER JOIN:

SELECT u.name, c.city_name
FROM users u
LEFT JOIN cities c ON u.city_id = c.id;

INNER JOIN возвращает только строки где есть совпадение в обеих таблицах. LEFT JOIN возвращает все строки из левой таблицы (users), а для тех у кого нет города - ставит NULL в колонку city_name.

Аватар Алиса Морозова

WHERE c.id IS NULL добавь в конец запроса.

Аватар Виктор Кузнецов

Спасибо, заработало! Теперь понял разницу. А если хочу показать только пользователей БЕЗ города - как фильтровать?

54
Участник • 2 ответа

Разберем все виды JOIN чтобы ты понял логику, а не просто скопировал ответ.

INNER JOIN - пересечение. Строки возвращаются только если ключ есть в обеих таблицах. Пользователь без city_id или с city_id которого нет в таблице cities - пропадает.

LEFT JOIN - все из левой таблицы плюс совпадения из правой. Пользователь без города останется, city_name будет NULL.

RIGHT JOIN - зеркально, все из правой. Редко используется, обычно просто меняют порядок таблиц и пишут LEFT.

FULL OUTER JOIN - все строки из обеих таблиц. В MySQL нет нативно, эмулируется через UNION.

Для твоей задачи нужен LEFT JOIN. Это 90% реальных запросов с соединением таблиц - один главный объект (users) и опциональные данные к нему (город).

19
Эксперт • 1 ответ

Кстати если хочешь понять JOIN визуально - загугли "SQL joins venn diagram". Картинка с кругами Эйлера объяснит за 10 секунд то что я писал бы 3 абзаца.

11
Эксперт • 1 ответ

Небольшая ремарка к ответам выше: в вашем запросе лучше явно указывать алиасы таблиц (u и c как в примере выше), это не только читаемость, но и обязательно когда одинаковые имена колонок встречаются в обеих таблицах - без алиаса MySQL выдаст ошибку неоднозначности.

3
Участник • 2 ответа

Попробуй USING вместо ON если имена ключей совпадают:

SELECT name, city_name FROM users LEFT JOIN cities USING(id);

Короче пишется... хотя стоп, у тебя разные имена (city_id и id), так что не прокатит. Оставь ON как в первом ответе.

8
Участник • 1 ответ

у меня тоже поначалу путаница с джойнами была, потом понял что INNER это "И то И то должно быть", LEFT это "хотя бы это" - после такого запомнилось навсегда

Написать ответ

Премодерация гостей

Вы отвечаете как гость. Ваш ответ будет скрыт до проверки модератором. Чтобы ответ появился сразу и вы получали репутацию — войдите в аккаунт.

Будьте вежливы и соблюдайте правила платформы.