0Pricing
SQL Interview Prep · Урок

ON и WHERE в объединениях

Узнайте, когда предикат должен находиться в ON, а когда в WHERE, и почему это влияет на результаты.

«ON и WHERE в объединениях» — бесплатный урок SQL Interview Prep на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения SQL Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс SQL Interview Prep содержит 4 уроков всего.

Предикат может находиться в двух местах

После того как Вы научились писать INNER JOIN, следующий вопрос на собеседовании становится более точным: должно ли это условие находиться в ON или в WHERE?

Для INNER JOIN ответ часто звучит так: «для результата это не имеет значения». Но как только Вы переключаетесь на внешнее соединение, выбор полностью меняет результат. Интервьюеры задают этот вопрос именно потому, что начинающие разработчики по привычке помещают всё в WHERE.

В этом уроке правило сформулировано предельно чётко.

Что делает ON

Предложение ON определяет, как образуются пары строк. Оно выполняется во время построения соединения и решает, какая строка левой таблицы соответствует какой строке правой.

Представляйте ON как ответ на вопрос: «относятся ли эти две строки друг к другу?»

SELECT c.name, o.amount
FROM customers c
JOIN orders o
  ON o.customer_id = c.id;   -- pairing rule

Что делает WHERE

Предложение WHERE выполняется после того, как соединение сформировало объединённые строки. Оно фильтрует этот набор результатов, отбрасывая строки, которые не проходят проверку.

Представляйте WHERE как ответ на вопрос: «теперь, когда строки соединены, какие из них я хочу оставить?»

SELECT c.name, o.amount
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.amount > 30;   -- filter after pairing

В INNER JOIN они часто дают один результат

Для INNER JOIN дополнительный фильтр даёт один и тот же результат независимо от того, помещён ли он в ON или WHERE. Оба приведённых ниже запроса возвращают только заказ Ады на $50 и заказ Боба на $99.

Поскольку несопоставленные строки уже отбрасываются внутренним соединением, перенос предиката не меняет набор оставшихся строк.

-- predicate in ON
SELECT c.name, o.amount FROM customers c
JOIN orders o
  ON o.customer_id = c.id AND o.amount > 30;

-- predicate in WHERE -- same result here
SELECT c.name, o.amount FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.amount > 30;

Почему стиль всё же требует использовать ON для ключей соединения

Даже когда результаты совпадают, принято помещать условия связи между таблицами в ON, а бизнес-фильтры — в WHERE.

  • ON: o.customer_id = c.id (как связаны таблицы)
  • WHERE: o.amount > 30 (какие результаты Вам нужны)

Такое разделение делает намерение очевидным и для следующего читателя, и для интервьюера, оценивающего Ваш стиль.

Где это действительно важно: внешние соединения

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

LEFT JOIN сохраняет Клео со значениями NULL в столбцах заказа. Теперь посмотрим, как ON и WHERE влияют на её строку.

SELECT c.name, o.amount
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id;
-- keeps Ada, Bob, AND Cleo (NULL amount)

Фильтр в ON: строки сохраняются

Поместите условие amount > 30 в ON при использовании LEFT JOIN — тогда оно влияет только на то, какие строки правой таблицы присоединяются. Несопоставленные строки левой таблицы всё равно сохраняются, только значения в них будут NULL.

Клео остаётся в результате. Любой заказ, который не проходит проверку, просто не присоединяется, и на его месте остаётся NULL.

SELECT c.name, o.amount
FROM customers c
LEFT JOIN orders o
  ON o.customer_id = c.id AND o.amount > 30;
-- Ada 50, Bob 99, Cleo NULL  (3 rows, Cleo kept)

Фильтр в WHERE: внешнее соединение схлопывается

Перенесите то же условие в WHERE, и Вы отфильтруете уже объединённый результат. В строке Клео значение amount = NULL, а условие NULL > 30 не является истинным, поэтому её строка удаляется.

LEFT JOIN незаметно начинает вести себя как INNER JOIN. Это самая известная ловушка с соединениями на собеседованиях.

SELECT c.name, o.amount
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.amount > 30;
-- Ada 50, Bob 99  (Cleo GONE -> back to inner-join behavior)

Правило, которое нужно запомнить

Сформулируйте это на собеседовании чётко:

  • Условие в ON решает, присоединяется ли строка правой таблицы; строки левой таблицы сохраняются.
  • Условие в WHERE фильтрует итоговые строки и может удалить сохранённые строки левой таблицы, если обращается к столбцу, который может содержать NULL.

Итак, для внешних соединений предикаты, относящиеся к необязательной таблице, помещайте в ON, если только намеренно не хотите удалить несопоставленные строки.

Допустимый случай использования WHERE с NULL

Есть один случай, когда фильтрация столбца внешнего соединения в WHERE абсолютно уместна: антисоединение. Проверка IS NULL находит строки левой таблицы, для которых не нашлось совпадения.

Здесь WHERE намеренно оставляет только несопоставленные строки и возвращает клиентов с нулевым количеством заказов. Механика та же, но намерение противоположное.

SELECT c.name
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;   -- customers with no orders -> Cleo

Быстрая мысленная проверка

Перед тестом используйте этот список, когда видите условие соединения:

  • Это ключ соединения, связывающий таблицы? -> ON.
  • Это фильтр по обязательной таблице? -> WHERE или ON — оба варианта подходят.
  • Это фильтр по необязательной (внешней) таблице, и Вы хотите сохранить несопоставленные строки? -> ON.
  • Вы хотите найти несопоставленные строки? -> WHERE ... IS NULL.

Быстрая проверка

Примените правило ON и WHERE к внешнему соединению.

Повторение: ON и WHERE

Основные моменты, которые стоит запомнить для собеседования:

  • ON управляет образованием пар и во внешних соединениях определяет, присоединяется ли необязательная строка, сохраняя при этом нужную сторону.
  • WHERE фильтрует уже объединённый результат и может удалить сохранённые строки.
  • В INNER JOIN эти два предложения часто взаимозаменяемы, а во внешних соединениях — нет.
  • Фильтры по внешней таблице следует помещать в ON, если только Вы намеренно не выполняете антисоединение с IS NULL в WHERE.

Часто задаваемые вопросы

Урок «ON и WHERE в объединениях» бесплатный?

Да — полный текст урока «ON и WHERE в объединениях» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс SQL Interview Prep, подпишись на CoddyKit PRO. Курс SQL Interview Prep содержит 4 уроков всего.

Чему я научусь в уроке «ON и WHERE в объединениях»?

Узнайте, когда предикат должен находиться в ON, а когда в WHERE, и почему это влияет на результаты. Ты практикуешь SQL Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать SQL Interview Prep?

Предыдущий опыт не требуется. SQL Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «ON и WHERE в объединениях»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке SQL Interview Prep?

Да. Каждый урок SQL Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Как INNER JOIN сопоставляет строки
  2. ON и WHERE в объединениях
  3. Размножение строк при JOIN
  4. Объединение трёх и более таблиц
← Назад к SQL Interview Prep