Как устроен SQL-запрос для вывода пользователей, которые брали книги, с объединением таблиц
Что проверяют
Умеете ли вы превратить формулировку задачи в правильную связь таблиц и не получить дубли. Следом почти всегда усложняют: вывести тех, кто не брал ни одной книги, посчитать книги на человека или отфильтровать по периоду.
Как отвечать
Сначала проговорите модель: пользователь берёт много книг, одну книгу берут многие, поэтому между users и books стоит таблица выдач loans (user_id, book_id, taken_at). Уточните у интервьюера, что именно нужно на выходе, от этого зависит запрос:
- список пар «кто что брал»:
usersсоединяется сloansпоuser_id, затемloansсbooksпоbook_id, оба раза черезINNER JOIN; - только пользователи: соединение даст строку на каждую выдачу, поэтому нужен
SELECT DISTINCT u.user_id, u.nameили, чище,WHERE EXISTS (SELECT 1 FROM loans l WHERE l.user_id = u.user_id).EXISTSостанавливается на первом совпадении и не размножает строки; - сколько книг взял каждый:
GROUP BY u.user_id, u.nameиCOUNT(l.book_id), либоCOUNT(DISTINCT l.book_id), если важны разные книги, а не число выдач. Порог вроде «больше трёх» задаётся вHAVING, не вWHERE; - кто не брал ничего:
LEFT JOIN loansиWHERE l.user_id IS NULL, либоNOT EXISTS; - за период: условие на
taken_at. ПриLEFT JOINего ставят вON, иначе пользователи без выдач за период выпадут из результата.
Хорошо звучит, если вы сами упомянете проверку: сравнить число строк до и после соединения и убедиться, что ключ в справочнике уникален. Для аналитика это главная защита от раздутых метрик.
Где спотыкаются
Пишут JOIN и выдают «список пользователей», в котором один человек повторяется по числу выдач. Затем по этому списку считают количество и получают завышенную цифру.
Ищут «не бравших» через NOT IN (SELECT user_id FROM loans). Если в подзапросе окажется хоть один NULL, запрос вернёт пустоту; у NOT EXISTS такой ловушки нет.
Кладут фильтр по правой таблице в WHERE после LEFT JOIN. Строки с NULL отсекаются, и внешнее соединение молча превращается во внутреннее.