JOIN: проверка связей между таблицами

До сих пор мы работали с одной таблицей за раз. Но в реальной базе нужные данные почти всегда разложены по НЕСКОЛЬКИМ связанным таблицам — как users, enrollments и courses из темы «Зачем тестировщику SQL. Таблицы, ключи, связи, типы данных». Чтобы собрать их вместе в одном запросе, нужен JOIN.

Чему научишься за этот урок:
— объяснять, зачем нужен JOIN и как он использует внешние ключи;
— писать запрос с несколькими JOIN, собирающий данные из трёх таблиц;
— называть разницу между INNER JOIN и LEFT JOIN;
— выбирать нужный вид JOIN под конкретный тестовый сценарий.

Зачем нужен JOIN

JOIN — объединение данных из нескольких таблиц в одном запросе по СВЯЗИ между ними, то есть через внешний ключ (поле, которое ссылается на первичный ключ другой таблицы). Без JOIN пришлось бы делать несколько отдельных запросов и вручную сопоставлять id между ними — JOIN делает это за один запрос.

INNER JOIN

INNER JOIN возвращает только те строки, для которых есть совпадение в ОБЕИХ таблицах. Если, например, у пользователя нет ни одной записи на курс — он просто не попадёт в результат INNER JOIN, потому что для него нет пары в таблице enrollments.

Начнём с самого простого случая — один JOIN между двумя таблицами:

SELECT enrollments.user_id, courses.title
FROM enrollments
JOIN courses ON enrollments.course_id = courses.id;

-- один JOIN, две таблицы: enrollments и courses
-- результат: для каждой записи на курс -- id пользователя и название курса

Теперь усложним пример: подключим сразу третью таблицу — users, — чтобы вместо голого user_id получить понятное имя пользователя:

SELECT users.name, courses.title
FROM enrollments
JOIN users ON enrollments.user_id = users.id
JOIN courses ON enrollments.course_id = courses.id;

-- просто JOIN без слова INNER работает как INNER JOIN (это значение по умолчанию)
-- результат: только пользователи, у которых ЕСТЬ хотя бы одна запись на курс

Обратите внимание: слово JOIN само по себе — это и есть INNER JOIN, слово INNER можно не писать явно, база подразумевает его по умолчанию.

LEFT JOIN

LEFT JOIN возвращает ВСЕ строки из левой (первой указанной) таблицы, даже если для них НЕТ совпадения в правой таблице. Если совпадения нет — поля из правой таблицы в результате будут NULL (пусто).

SELECT users.name, enrollments.course_id
FROM users
LEFT JOIN enrollments ON users.id = enrollments.user_id;

-- вернутся ВСЕ пользователи, даже те, у кого нет ни одной записи на курс
-- у таких пользователей enrollments.course_id в результате будет NULL

Практическая разница: когда какой JOIN нужен

Разница между видами JOIN — это не теория ради теории, а вопрос ПРАВИЛЬНОГО результата под конкретную задачу тестировщика:

Сценарий А: 'Показать всех пользователей, у которых ЕСТЬ хотя бы одна запись на курс'
-> нужен INNER JOIN (или просто JOIN)

Сценарий Б: 'Найти пользователей БЕЗ единой записи на курс' (например, для рассылки
'вы давно не заходили')
-> нужен LEFT JOIN + WHERE enrollments.id IS NULL
   (строки, где справа не нашлось совпадения -- как раз те, у кого нет записей)
SELECT users.name
FROM users
LEFT JOIN enrollments ON users.id = enrollments.user_id
WHERE enrollments.id IS NULL;

-- вернёт только тех пользователей, для кого справа не нашлось ни одной записи

Если бы для сценария Б по ошибке использовали INNER JOIN, запрос вернул бы пустой (или неполный) результат — пользователи без записей просто не попали бы в него ни при каких условиях WHERE, потому что INNER JOIN отбрасывает их ещё до фильтрации.

Итог:
— JOIN объединяет данные из нескольких таблиц по связи через внешний ключ;
— INNER JOIN (или просто JOIN) — только строки с совпадением в обеих таблицах;
— LEFT JOIN — все строки из левой таблицы, даже без совпадения справа (тогда поля справа — NULL);
— поиск ‘у кого чего-то нет’ требует LEFT JOIN + условие IS NULL на поле правой таблицы;
— выбор неверного вида JOIN даёт неполный или пустой результат, даже если сам запрос не содержит синтаксической ошибки.

Контрольный вопрос. Зачем в SQL нужен JOIN?

АЧтобы объединить данные таблиц по связи
БЧтобы ограничить число возвращаемых строк
ВЧтобы отсортировать данные таблицы по столбцам

Подсказка: В начале урока прямо дано определение JOIN.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Что вернёт INNER JOIN, если у пользователя нет ни одной записи на курс?

АТакой пользователь попадёт в результат с пустыми (NULL) полями по курсу
БТакой пользователь не попадёт в результат вообще
ВЗапрос завершится ошибкой

Подсказка: В уроке прямо сказано, что INNER JOIN требует совпадения в ОБЕИХ таблицах.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Что делает LEFT JOIN, если для строки левой таблицы нет совпадения в правой?

АОстанавливает выполнение всего запроса и выдаёт ошибку
БВключает строку в результат, поля правой таблицы — NULL
ВПолностью исключает такую строку из итогового результата

Подсказка: Ключевая разница LEFT JOIN с INNER JOIN — что происходит именно в этом случае.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Что означает просто ключевое слово JOIN без уточнения INNER или LEFT?

АЭто LEFT JOIN — значение по умолчанию
БТакой запрос всегда некорректен и требует явного уточнения
ВЭто INNER JOIN — значение по умолчанию

Подсказка: В уроке это отмечено отдельным замечанием сразу после первого примера с JOIN.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Дан запрос: SELECT users.name FROM users LEFT JOIN enrollments ON users.id = enrollments.user_id WHERE enrollments.id IS NULL; Какие из утверждений про него верны (выбери все подходящие)?

Выберите все верные варианты.

АЗапрос вернёт пользователей, у которых нет ни одной записи на курс
БLEFT JOIN оставляет только тех пользователей, для которых нашлось совпадение в enrollments
ВЕсли заменить LEFT JOIN на INNER JOIN в этом запросе, результат гарантированно останется тем же
ГБез условия WHERE этот запрос вернул бы только пользователей, записанных хотя бы на один курс
ДУсловие WHERE enrollments.id IS NULL отбирает как раз те строки, где справа не нашлось совпадения
ЕТакой запрос подходит для сценария ‘найти пользователей для рассылки тем, кто ещё не записался ни на один курс’

Подсказка: Одно утверждение прямо противоречит разнице между INNER JOIN и LEFT JOIN, разобранной в уроке.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Какой вид JOIN нужен, чтобы вернуть ВСЕ строки из первой (левой) таблицы, даже без совпадения во второй? Ответь двумя словами по-английски, как в уроке.

Подсказка: Название этого вида JOIN отражает, из какой таблицы берутся все строки.

Онлайн-проверка ответа появится позже

Задание. На основе какой связи между таблицами работает JOIN — через какой вид ключа? Ответь двумя словами по-русски.

Подсказка: Это ключ, который хранится в одной таблице, а указывает на первичный ключ другой.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Задание. Тестировщик выполнил запрос с INNER JOIN между users и enrollments и получил 40 строк, хотя в таблице users всего 50 пользователей. Известно, что у каждого пользователя в enrollments не больше одной записи (каждый записан максимум на один курс). Сколько пользователей из 50 не попали в результат? Ответь числом.

Подсказка: Вспомни, кого INNER JOIN отбрасывает из результата. Раз у каждого пользователя не больше одной записи, одна строка результата — это один пользователь.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Задание. Даны два тестовых сценария:
Сценарий 1: нужен список пользователей ВМЕСТЕ с названиями курсов, на которые они записаны, но интересуют ТОЛЬКО те, у кого есть хотя бы одна запись.
Сценарий 2: нужен список ВСЕХ пользователей, включая тех, кто ещё ни на один курс не записался, чтобы отправить им письмо с предложением записаться.
Для каждого сценария укажи, какой вид JOIN нужен (INNER JOIN или LEFT JOIN), и обоснуй выбор в 1-2 предложениях на сценарий.

Подсказка: Ключевое слово в каждом сценарии — ‘только те, у кого есть’ против ‘все, включая тех, у кого нет’.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Задание. Тестировщик по ошибке использовал INNER JOIN вместо LEFT JOIN в запросе, который должен был найти пользователей БЕЗ единой записи на курс (для сценария ‘давно не заходили’). Объясни в 2-3 предложениях: (а) что вернёт такой ошибочный запрос — пустой результат или что-то другое, и почему; (б) как правильно переписать запрос, используя LEFT JOIN и условие на NULL.

Подсказка: Подумай, в какой момент INNER JOIN отбрасывает нужные строки — до или после условия WHERE IS NULL, и может ли это условие вообще на что-то сработать после INNER JOIN.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Что дальше

Теперь вы умеете собирать данные из нескольких связанных таблиц и выбирать правильный вид JOIN под сценарий. Дальше — новые приёмы работы с данными.

Хотите глубже? Запрос SELECT во всех подробностях, с примерами — в статье «Запрос SELECT SQL. Получение информации из базы данных.».

← Назад  ·  ↑ В начало урока  ·  ⌂ В начало курса  ·  Вперёд →

Школа Виктора Комлева