Как устроен SQL-запрос с объединением нескольких таблиц
Что проверяют
Понимаете ли вы, как соединение меняет число строк, а не только синтаксис JOIN. Для аналитика следом обычно спрашивают, почему после соединения выросла сумма выручки и как это исправить.
Как отвечать
Начните с логического порядка выполнения, из него следуют почти все правила: FROM и JOIN собирают набор строк, затем WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT. Поэтому псевдоним из SELECT нельзя использовать в WHERE, а фильтр в WHERE применяется уже к соединённым строкам.
Типы соединений:
INNER JOIN: только строки, для которых нашлась пара по условиюON;LEFT JOIN: все строки левой таблицы, у несовпавших поля правой заполненыNULL.RIGHT JOINзеркален ему, на практике его переписывают вLEFT;FULL OUTER JOIN: все строки обеих таблиц,NULLтам, где пары нет. В MySQL его нет, эмулируют черезUNIONдвух внешних соединений;CROSS JOIN: декартово произведение, полезно для сетки «все даты на все категории»;- self join: таблица с самой собой, например сотрудник и его руководитель в одной таблице.
При нескольких таблицах каждое следующее соединение применяется к результату предыдущего. Главное здесь зернистость: если к заказам присоединить и позиции, и платежи, у каждого заказа строк станет «позиции × платежи», и SUM по платежам вырастет в разы. Лечится предварительной агрегацией в подзапросе или CTE до соединения.
Где спотыкаются
Описывают FULL JOIN как «строки, где есть совпадение в одной из таблиц». Это неточно: он возвращает всё из обеих таблиц, а совпавшие строки склеивает.
Ставят условие на правую таблицу в WHERE после LEFT JOIN. Строки с NULL отбрасываются, и внешнее соединение становится внутренним; такое условие переносят в ON.
Не проверяют ключи. NULL в колонке соединения не равен ничему, даже другому NULL, и такие строки тихо теряются, а неуникальный ключ в справочнике размножает факты. Прежде чем строить отчёт, сравните COUNT(*) до и после каждого соединения.