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 > 20IN как проверка принадлежности множеству
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— удобная проверка принадлежности множеству, безопасная при наличии NULLNOT 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 — локальная установка не требуется.
Все уроки этого курса
- Приоритет AND и OR и расстановка скобок
- BETWEEN, IN и включение границ
- LIKE, подстановочные символы и экранирование
- Фильтрация по вычисляемым значениям