WHERE в SQL — полный гайд по фильтрации данных
Коротко
WHERE -- оператор фильтрации строк в SQL. Без него любой SELECT возвращает всю таблицу целиком, а аналитику почти всегда нужна только часть данных: заказы за последний месяц, активные пользователи, события с определённым статусом. На собеседовании по SQL WHERE -- первое, что проверяют, потому что фильтрация лежит в основе любого запроса.
Синтаксис WHERE
SELECT column1, column2
FROM table_name
WHERE conditionWHERE стоит после FROM и выполняется до GROUP BY, HAVING и ORDER BY. Строки, для которых условие даёт TRUE, попадают в результат. Строки с FALSE или NULL -- отбрасываются.
Операторы сравнения
| Оператор | Значение | Пример |
|---|---|---|
= |
Равно | WHERE status = 'active' |
<> или != |
Не равно | WHERE status <> 'deleted' |
> |
Больше | WHERE amount > 1000 |
< |
Меньше | WHERE age < 30 |
>= |
Больше или равно | WHERE rating >= 4.5 |
<= |
Меньше или равно | WHERE attempts <= 3 |
Все операторы работают со строками, числами и датами. Строки сравниваются лексикографически (по алфавиту с учётом регистра).
AND, OR, NOT и приоритет операторов
AND и OR комбинируют несколько условий. NOT инвертирует условие.
SELECT *
FROM users
WHERE status = 'active'
AND created_at >= '2025-01-01'Приоритет: AND выполняется раньше OR. Это главный источник ошибок. Без скобок запрос работает не так, как кажется:
-- НЕПРАВИЛЬНО: AND связывает status и channel, OR "висит" отдельно
WHERE channel = 'organic' OR channel = 'referral' AND status = 'active'
-- Эквивалентно: channel = 'organic' OR (channel = 'referral' AND status = 'active')
-- ПРАВИЛЬНО: скобки явно задают логику
WHERE (channel = 'organic' OR channel = 'referral') AND status = 'active'Правило: если в WHERE есть и AND, и OR -- всегда ставьте скобки. Даже если приоритет правильный, скобки делают запрос читаемым.
IN -- список значений или подзапрос
IN проверяет, входит ли значение в набор:
-- список значений
SELECT *
FROM orders
WHERE status IN ('paid', 'shipped', 'delivered')
-- подзапрос
SELECT *
FROM users
WHERE user_id IN (
SELECT user_id
FROM orders
WHERE amount > 10000
)IN (список) -- короткая альтернатива цепочке OR. NOT IN -- инвертирует. Осторожно с NULL в списке: NOT IN (1, 2, NULL) вернёт пустой результат, потому что x <> NULL даёт NULL, а не TRUE.
BETWEEN -- диапазон значений
SELECT *
FROM orders
WHERE amount BETWEEN 1000 AND 5000BETWEEN включает обе границы -- эквивалентно amount >= 1000 AND amount <= 5000. Работает с числами, датами и строками.
IS NULL / IS NOT NULL
NULL -- это «нет значения», и обычные операторы сравнения с ним не работают:
-- НЕПРАВИЛЬНО: всегда вернёт 0 строк
WHERE city = NULL
-- ПРАВИЛЬНО
WHERE city IS NULL
WHERE city IS NOT NULL= NULL не равно IS NULL. Любое сравнение с NULL через =, <>, > даёт NULL (не TRUE и не FALSE). Это одна из самых частых ошибок на собеседовании.
LIKE -- поиск по шаблону
LIKE фильтрует строки по шаблону с подстановочными символами:
-- email на gmail.com
WHERE email LIKE '%@gmail.com'
-- имя из 4 букв, начинается на 'А'
WHERE name LIKE 'А___'% -- любое количество символов, _ -- ровно один. Подробнее -- в гайде по LIKE.
WHERE с датами
Даты -- один из самых частых фильтров в аналитике:
-- события за последние 7 дней
SELECT *
FROM events
WHERE created_at >= CURRENT_DATE - INTERVAL '7 days'
-- события за конкретный месяц
SELECT *
FROM events
WHERE created_at >= '2025-03-01'
AND created_at < '2025-04-01'Для диапазонов дат используйте >= и < (не BETWEEN) -- так вы исключаете начало следующего периода и не теряете записи с временем 23:59:59.
WHERE с агрегатами -- нельзя! Используйте HAVING
WHERE фильтрует строки до группировки. Поэтому использовать агрегатные функции в WHERE нельзя:
-- ОШИБКА: WHERE не знает про COUNT
SELECT department, COUNT(*) AS cnt
FROM employees
WHERE COUNT(*) > 5
GROUP BY department
-- ПРАВИЛЬНО: HAVING фильтрует после группировки
SELECT department, COUNT(*) AS cnt
FROM employees
GROUP BY department
HAVING COUNT(*) > 5Порядок выполнения: FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY. WHERE работает до GROUP BY, HAVING -- после.
Практические примеры
Активные пользователи за период:
SELECT user_id, username, last_active_at
FROM users
WHERE status = 'active'
AND last_active_at >= CURRENT_DATE - INTERVAL '30 days'Заказы с непустым промокодом в определённом диапазоне сумм:
SELECT order_id, amount, promo_code
FROM orders
WHERE amount BETWEEN 500 AND 10000
AND promo_code IS NOT NULLПользователи из конкретных городов, исключая тестовые аккаунты:
SELECT user_id, email, city
FROM users
WHERE city IN ('Москва', 'Санкт-Петербург', 'Казань')
AND email NOT LIKE '%@test.%'Типичные ошибки
= NULL вместо IS NULL. WHERE city = NULL всегда возвращает 0 строк. NULL -- не значение, а отсутствие значения. Для проверки на NULL используйте только IS NULL / IS NOT NULL.
OR без скобок. WHERE a = 1 OR b = 2 AND c = 3 -- AND выполнится первым. Результат: a = 1 OR (b = 2 AND c = 3), а не (a = 1 OR b = 2) AND c = 3. Всегда ставьте скобки.
NOT IN с NULL. WHERE id NOT IN (1, 2, NULL) вернёт пустой результат. Если в подзапросе может быть NULL -- используйте NOT EXISTS или добавьте WHERE ... IS NOT NULL в подзапрос.
BETWEEN с датами и временем. WHERE created_at BETWEEN '2025-03-01' AND '2025-03-31' пропустит записи 31 марта с временем после 00:00:00. Используйте >= '2025-03-01' AND < '2025-04-01'.
Вопросы с собеседований
-- Чем WHERE отличается от HAVING? -- WHERE фильтрует строки до группировки, HAVING -- после. В WHERE нельзя использовать агрегатные функции (COUNT, SUM и т.д.), в HAVING -- можно. Подробнее: WHERE vs HAVING.
-- Почему WHERE column = NULL не работает?
-- Потому что любое сравнение с NULL через = возвращает NULL, а не TRUE. NULL означает «неизвестно», и неизвестно = неизвестно -- это не TRUE. Для проверки используется IS NULL.
-- В каком порядке выполняются части SQL-запроса? -- FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT. WHERE выполняется вторым -- сразу после определения источника данных.
-- Чем IN отличается от EXISTS? -- IN сравнивает значение со списком. EXISTS проверяет, вернул ли подзапрос хотя бы одну строку. На больших подзапросах EXISTS может быть быстрее, потому что останавливается при первом совпадении. Главное отличие: NOT IN ломается при NULL в подзапросе, NOT EXISTS -- нет.
-- Напишите запрос: пользователи, зарегистрировавшиеся в январе 2025 из Москвы или Питера, которые сделали хотя бы один заказ.
-- SELECT u.user_id, u.name FROM users u WHERE u.city IN ('Москва', 'Санкт-Петербург') AND u.created_at >= '2025-01-01' AND u.created_at < '2025-02-01' AND EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.user_id).
Потренируйтесь в тренажёре
WHERE -- фундамент SQL, и на собеседовании его проверяют не отдельно, а в связке с JOIN, GROUP BY и подзапросами. Потренируйтесь писать запросы с фильтрацией -- откройте тренажёр с 200+ задачами по SQL и разборами.
FAQ
Можно ли использовать алиас из SELECT в WHERE?
Нет. WHERE выполняется до SELECT, поэтому алиас ещё не существует. WHERE total_amount > 1000 не сработает, если total_amount -- алиас. Повторите выражение: WHERE SUM(amount) > 1000 -- тоже нельзя (агрегат в WHERE). Вынесите в подзапрос или используйте HAVING.
WHERE лучше, чем HAVING, для фильтрации?
Да, если фильтр не зависит от агрегатной функции. WHERE отсекает строки до группировки -- меньше данных обрабатывается в GROUP BY, быстрее запрос. Фильтруйте через WHERE всё, что можно, а HAVING оставляйте только для условий на агрегаты.
Как фильтровать по нескольким условиям одного столбца?
Используйте IN вместо цепочки OR: WHERE status IN ('active', 'pending', 'trial') -- короче и читаемее, чем WHERE status = 'active' OR status = 'pending' OR status = 'trial'. Для диапазонов -- BETWEEN или >= и <=.
Влияет ли порядок условий в WHERE на производительность?
В теории -- нет. Оптимизатор СУБД сам решает, в каком порядке проверять условия и какие индексы использовать. На практике стоит ставить наиболее селективное условие первым -- не ради скорости, а ради читаемости.
Как тренироваться
WHERE встречается в каждом SQL-запросе, и на собеседовании вас будут проверять на нюансах: NULL, приоритет AND/OR, даты с временем. В тренажёре Карьерник есть задачи на фильтрацию с разборами -- тренируйтесь по 15 минут в день, и ошибки уйдут.
Больше вопросов по SQL -- в примерах вопросов по всем темам.