Задачи на JOIN в SQL
JOIN·middle

Фильмы, которых нет ни на одной полке

Задача

Костя из закупок просит инвентаризацию: «В каталоге тысяча фильмов, но часть из них мы, кажется, никогда не завозили на диски. Найди фильмы, которых нет ни в одной копии на складе, — решим, докупать или выпиливать из каталога».

Верни film_id и название всех фильмов, у которых нет ни одной записи в инвентаре.

Схема данных

Учебная база проката dvdrental:

  • film(film_id, title, ...) — каталог фильмов.
  • inventory(inventory_id, film_id, ...) — физические копии дисков; каждая строка — один диск конкретного фильма. У фильма без копий записей тут просто нет.

Решение

SELECT f.film_id, f.title
FROM film f
LEFT JOIN inventory i ON i.film_id = f.film_id
WHERE i.film_id IS NULL
ORDER BY f.title;

Разбор

Это классический анти-джойн — «найди то, чего нет в другой таблице». Прямой INNER JOIN вернул бы только фильмы, у которых копии есть, а нам нужно ровно противоположное. Приём в два шага.

Сначала LEFT JOIN: он берёт все строки левой таблицы film и подтягивает совпадения из inventory. Для фильма, у которого копий нет, совпадений не находится — и Postgres подставляет в колонки inventory значения NULL. То есть после соединения такие фильмы никуда не делись, они просто «пустые» справа.

Второй шаг — WHERE i.film_id IS NULL. Это фильтр ровно по тем строкам, где справа пусто, то есть по фильмам без единой копии. Важно писать именно IS NULL, а не = NULL: сравнение = NULL в SQL всегда даёт «неизвестно», и такой фильтр не вернёт ни строки. Почему так — в вопросе как NULL ведёт себя в SQL.

Тонкость про количество строк: LEFT JOIN иногда пугают тем, что он «размножает» левую таблицу, если справа несколько совпадений. Здесь это работает нам на руку — но нас интересуют как раз строки БЕЗ совпадений, где размножения нет по определению. Полный разбор эффекта — в вопросе может ли LEFT JOIN вернуть больше строк.

Тот же результат можно получить через WHERE NOT EXISTS (...) — этот вариант разбираем в задаче клиенты, бравшие боевики, только там условие обратное, «где совпадение есть».

Ожидаемый результат

film_id | title
--- | ---
14 | Alice Fantasia
33 | Apollo Teen
36 | Argonauts Town
38 | Ark Ridgemont
41 | Arsenic Independence
87 | Boondock Ballroom
108 | Butch Panther
128 | Catch Amistad
144 | Chinatown Gladiator
148 | Chocolate Duck
… всего строк: 42 (показаны первые 10)

Прорешай такие задачи сам

Читать разбор полезно, а настоящая прокачка — самому писать запросы и получать обратную связь. В симуляторе живая база и проверка запросов, лёгкий режим — бесплатно.

Прорешать в бесплатной песочнице

Смежные задачи

Вопросы по теме