0Pricing
SQL Interview Prep · Урок

BETWEEN, IN и включение границ

Разбирайте пограничные случаи и то, как BETWEEN обрабатывает конечные точки.

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

Почему из-за границ кандидаты теряют баллы

Фильтры по диапазону и множеству кажутся простыми, поэтому интервьюеры любят использовать против кандидатов пограничные случаи. BETWEEN включает обе границы, в IN скрыта тонкая ловушка с NULL, а диапазоны дат приводят к ошибкам на единицу, незаметно искажая отчёты.

В этом уроке точно разбирается, как BETWEEN обрабатывает свои границы, когда IN понятнее цепочки OR и какой шаблон полуоткрытого диапазона профессионалы используют для дат.

BETWEEN включает обе границы

col BETWEEN a AND b — это сокращение для col >= a AND col <= b. Обе границы включаются.

Поэтому price BETWEEN 10 AND 20 возвращает строки, где цена равна ровно 10 или ровно 20, а также все значения между ними. Самый распространённый неправильный ответ на собеседовании — утверждение, что верхняя граница исключается.

SELECT *
FROM products
WHERE price BETWEEN 10 AND 20;
-- equivalent to: price >= 10 AND price <= 20

Порядок аргументов имеет значение

BETWEEN требует указывать сначала меньшее значение. col BETWEEN 20 AND 10 разворачивается в col >= 20 AND col <= 10, что никогда не может быть истинным, поэтому возвращает ноль строк, а не ошибку.

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

SELECT *
FROM products
WHERE price BETWEEN 20 AND 10;
-- returns NOTHING, not an error

Ошибка на единицу в диапазоне дат

Когда просят выбрать весь январь, многие кандидаты пишут order_date BETWEEN '2024-01-01' AND '2024-01-31'. Если order_date имеет тип метки времени, этот запрос отбрасывает всё после полуночи 31 января, потому что 2024-01-31 означает 2024-01-31 00:00:00.

Заказ в два часа дня 31 января не попадёт в результат. Для столбцов типа DATE это работает, но нельзя заранее предполагать тип.

SELECT *
FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-01-31';
-- silently excludes Jan 31 afternoon if order_date is a timestamp

Исправление: полуоткрытый диапазон

Профессиональный шаблон для дат — это полуоткрытый интервал: больше либо равно началу и строго меньше следующего периода. Он корректен и для DATE, и для TIMESTAMP и не требует знать точность времени столбца.

Обратите внимание: верхняя граница — это первый день февраля, а не последний день января. Так охватывается каждый момент января.

SELECT *
FROM orders
WHERE order_date >= '2024-01-01'
  AND order_date <  '2024-02-01';

NOT BETWEEN

col NOT BETWEEN a AND b разворачивается в col < a OR col > b. Он исключает обе границы и всё, что находится между ними.

Будьте внимательны: если col равен NULL, выражение NOT BETWEEN вычисляется как UNKNOWN, поэтому строки с NULL исключаются так же, как и при обычном BETWEEN. NULL никогда не удовлетворяет проверке диапазона ни в одном направлении.

SELECT *
FROM products
WHERE price NOT BETWEEN 10 AND 20;
-- price < 10 OR price > 20

IN как проверка принадлежности множеству

col IN (a, b, c) — это сокращение для col = a OR col = b OR col = c. Это удобный способ проверить принадлежность небольшому фиксированному множеству.

Такой запрос читается лучше, чем цепочка OR, и полностью устраняет проблему со скобками приоритетов, поскольку вся проверка множества представляет собой один предикат.

SELECT *
FROM orders
WHERE status IN ('pending', 'shipped', 'delivered');

Ловушка NULL в NOT IN

Это самый пугающий вопрос про IN. Если список или подзапрос, лежащий в основе NOT IN, содержит хотя бы один NULL, весь предикат может вычислиться как UNKNOWN и вернуть ноль строк.

Причина: x NOT IN (1, NULL) превращается в x <> 1 AND x <> NULL, а x <> NULL никогда не бывает истинным — это UNKNOWN. Всё условие AND не может быть истинным.

SELECT *
FROM employees
WHERE manager_id NOT IN (SELECT id FROM managers);
-- returns NOTHING if any managers.id is NULL

Исправление NOT IN

Два надёжных способа исправить ловушку с NULL в NOT IN:

  • Исключите NULL из подзапроса с помощью WHERE id IS NOT NULL
  • Ещё лучше — перепишите условие с использованием NOT EXISTS, который по своей конструкции корректно обрабатывает NULL

Интервьюеры считают NOT EXISTS ответом опытного специалиста, потому что он полностью обходит эту ловушку и часто позволяет построить более эффективный план.

SELECT e.*
FROM employees e
WHERE NOT EXISTS (
  SELECT 1 FROM managers m WHERE m.id = e.manager_id
);

IN с подзапросом

IN принимает подзапрос, возвращающий один столбец. WHERE customer_id IN (SELECT customer_id FROM vip) оставляет строки, где клиент входит в набор VIP.

Обычный IN (не NOT IN) безопасен при наличии NULL в подзапросе: NULL в списке просто никогда не совпадает, но не влияет на строки, которые совпали. Ловушка относится только к NOT IN.

SELECT *
FROM orders
WHERE customer_id IN (SELECT customer_id FROM vip_customers);

Многостолбцовый IN с конструкторами строк

Распространённый дополнительный вопрос: как сопоставлять значения сразу по нескольким столбцам? Передайте кортеж в IN с помощью конструктора строк — он сравнивает столбцы по позициям и гораздо понятнее длинной цепочки OR (a = .. AND b = ..).

  • Такой запрос легко читать, и он подходит для длинных списков разрешённых значений.
  • В каждом кортеже столбцы должны быть перечислены в одном и том же порядке.
SELECT *
FROM orders
WHERE (customer_id, status) IN ((101, 'paid'), (102, 'shipped'));

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

Вспомните, как BETWEEN обрабатывает свои границы.

Итоги

Основные выводы:

  • BETWEEN a AND b включает обе границы; нижняя граница должна быть указана первой, иначе Вы получите ноль строк
  • Для диапазонов TIMESTAMP используйте полуоткрытый интервал: >= start AND < next_period
  • IN — удобная проверка принадлежности множеству, безопасная при наличии NULL
  • NOT IN с любым NULL в списке ничего не возвращает; перепишите его как NOT EXISTS

Главная повторяющаяся мысль: фильтр может выполниться безупречно и всё же незаметно вернуть не те строки.

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

Урок «BETWEEN, IN и включение границ» бесплатный?

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

Чему я научусь в уроке «BETWEEN, IN и включение границ»?

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

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

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

Сколько времени занимает урок «BETWEEN, IN и включение границ»?

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

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

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

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

  1. Приоритет AND и OR и расстановка скобок
  2. BETWEEN, IN и включение границ
  3. LIKE, подстановочные символы и экранирование
  4. Фильтрация по вычисляемым значениям
← Назад к SQL Interview Prep