SQLWHEREtutorialbeginner

Что такое WHERE в SQL?

WHERE — фильтр строк в SQL. Простыми словами и на пальцах: =, IN, BETWEEN, LIKE, IS NULL и AND/OR. Куча примеров с таблицами «до и после», частые ошибки новичков и мини-практика в конце.

14 мин чтенияСправочникSQL · WHERE · tutorial · beginner

WHERE — это фильтр для строк.

Без WHERE запрос берёт всё подряд из таблицы.
С WHERE — только те строки, которые подходят под условие.

Представь таблицу как большой шкаф с вещами. Запрос без фильтра — это «достань весь шкаф на пол». А запрос с WHERE — «достань только красные футболки размера L». SQL не тащит лишнее, а сразу отбирает нужное.

Простой пример:

SELECT name, age
FROM users
WHERE age >= 18;

Такой запрос читает таблицу users, но возвращает не всех пользователей, а только тех, кому 18 лет или больше.

Зачем нужен WHERE

В учебной таблице может быть 5 строк. В настоящей базе — тысячи, миллионы или десятки миллионов.

Если каждый раз доставать всю таблицу целиком, будет плохо:

  • база сделает лишнюю работу;
  • приложение получит слишком много данных;
  • запрос станет медленнее;
  • нужную информацию будет сложнее найти;
  • можно случайно показать пользователю не те данные.

WHERE решает эту проблему. Он отсекает лишние строки прямо на стороне базы данных.

Например, тебе нужны не все заказы, а только оплаченные:

SELECT id, amount, status
FROM orders
WHERE status = 'paid';

Или не все товары, а только дорогие:

SELECT name, price
FROM products
WHERE price > 1000;

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

SELECT id, name, email
FROM users
WHERE email = 'alice@example.com';

WHERE — одна из самых важных частей SQL. Без него невозможно нормально искать, обновлять и удалять данные.

Как WHERE работает внутри запроса

Когда база видит запрос с WHERE, она проверяет условие для каждой строки.

Например:

SELECT name, age
FROM users
WHERE age > 18;

База рассуждает примерно так:

  1. Берёт первую строку.
  2. Смотрит значение age.
  3. Проверяет условие age > 18.
  4. Если условие истинно — строка попадает в результат.
  5. Если условие ложно — строка отбрасывается.
  6. Переходит к следующей строке.

То есть WHERE — это проверка «подходит строка или нет».

Важно: WHERE фильтрует строки, а SELECT выбирает колонки.

SELECT name, age
FROM users
WHERE age > 18;

Здесь:

  • SELECT name, age говорит, какие колонки показать;
  • FROM users говорит, из какой таблицы брать данные;
  • WHERE age > 18 говорит, какие строки оставить.

Первый пример с таблицей

Есть таблица products.

id name price
1 Mug 350
2 Kettle 1200
3 Microwave 5000
4 Spoon 80

Нужно получить товары дороже 1000.

SELECT name, price
FROM products
WHERE price > 1000;

Результат:

name price
Kettle 1200
Microwave 5000

Mug и Spoon не попали в результат, потому что их цена меньше или равна 1000.

Операторы сравнения

В WHERE часто используют обычные сравнения.

Оператор Значение
= равно
<> не равно
!= не равно, поддерживается во многих СУБД
> больше
< меньше
>= больше или равно
<= меньше или равно

Примеры:

SELECT name, price
FROM products
WHERE price = 1200;
SELECT name, price
FROM products
WHERE price <> 1200;
SELECT name, price
FROM products
WHERE price <= 1000;

Со строками сравнение тоже работает:

SELECT id, name, country
FROM users
WHERE country = 'Russia';

Строковые значения пишутся в одинарных кавычках.

Числа — без кавычек:

SELECT id, name, age
FROM users
WHERE age >= 21;

AND: когда должны выполниться все условия

AND означает «и».

Строка попадёт в результат только если все условия истинны.

Например:

SELECT id, name, country, age
FROM users
WHERE country = 'Russia' AND age >= 21;

Читается так:

Верни пользователей, у которых страна Russia и возраст 21 или больше.

Есть таблица users.

id name country age
1 Anna Russia 25
2 Bob USA 30
3 Vera Russia 17
4 Grigory Russia 40

Запрос:

SELECT name
FROM users
WHERE country = 'Russia' AND age >= 21;

Результат:

name
Anna
Grigory

Почему?

  • Anna подходит: страна Russia, возраст 25.
  • Bob не подходит: возраст подходит, но страна USA.
  • Vera не подходит: страна подходит, но возраст 17.
  • Grigory подходит: страна Russia, возраст 40.

Для AND нужно, чтобы совпало всё.

OR: когда достаточно одного условия

OR означает «или».

Строка попадёт в результат, если истинно хотя бы одно условие.

Возьмём ту же таблицу:

id name country age
1 Anna Russia 25
2 Bob USA 30
3 Vera Russia 17
4 Grigory Russia 40

Запрос:

SELECT name
FROM users
WHERE country = 'Russia' OR age >= 21;

Результат:

name
Anna
Bob
Vera
Grigory

Теперь попали все:

  • Anna подходит по обоим условиям;
  • Bob подходит по возрасту;
  • Vera подходит по стране;
  • Grigory подходит по обоим условиям.

OR шире, чем AND. Он пропускает больше строк.

NOT: отрицание условия

NOT переворачивает условие.

Например, найти заказы, которые не отменены:

SELECT id, status, amount
FROM orders
WHERE NOT status = 'cancelled';

То же самое обычно пишут проще:

SELECT id, status, amount
FROM orders
WHERE status <> 'cancelled';

Ещё пример: найти товары, которых нет в наличии.

SELECT id, name, in_stock
FROM products
WHERE NOT in_stock;

Такой запрос удобен, если in_stock — булева колонка со значениями TRUE или FALSE.

Скобки в сложных условиях

Когда в одном условии есть и AND, и OR, лучше ставить скобки.

Вот пример:

SELECT id, name, country, age, tier
FROM users
WHERE country = 'Russia'
  AND (tier = 'gold' OR age >= 30);

Читается так:

Верни пользователей из Russia, у которых тариф gold или возраст 30+.

Скобки помогают человеку сразу увидеть логику.

Без скобок SQL тоже умеет вычислять выражения по приоритетам: AND выполняется раньше, чем OR. Но новичку легко ошибиться и получить не тот результат.

Лучше писать явно:

WHERE country = 'Russia'
  AND (tier = 'gold' OR age >= 30)

чем надеяться, что и ты, и база поняли условие одинаково.

IN: значение входит в список

IN используют, когда нужно проверить значение по списку вариантов.

Например, нужны пользователи из нескольких стран:

SELECT id, name, country
FROM users
WHERE country IN ('Russia', 'Belarus', 'Kazakhstan');

Это короче и понятнее, чем длинная цепочка через OR:

SELECT id, name, country
FROM users
WHERE country = 'Russia'
   OR country = 'Belarus'
   OR country = 'Kazakhstan';

Смысл один и тот же, но IN читается спокойнее.

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

Например:

SELECT id, status, amount
FROM orders
WHERE status IN ('paid', 'shipped', 'delivered');

NOT IN: значение не входит в список

Есть обратная форма — NOT IN.

SELECT id, name, country
FROM users
WHERE country NOT IN ('USA', 'Canada');

Такой запрос вернёт пользователей, у которых страна не USA и не Canada.

Но с NOT IN нужно быть внимательным, если внутри списка или подзапроса может появиться NULL. NULL в SQL ведёт себя особенным образом, и результат может оказаться неожиданным.

Для обычного явного списка без NULL всё просто:

WHERE status NOT IN ('cancelled', 'failed')

Это значит: статус не должен быть ни cancelled, ни failed.

BETWEEN: значение находится в диапазоне

BETWEEN проверяет, попадает ли значение в диапазон.

Например, товары от 100 до 500:

SELECT name, price
FROM products
WHERE price BETWEEN 100 AND 500;

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

То есть это условие:

WHERE price BETWEEN 100 AND 500

равносильно этому:

WHERE price >= 100 AND price <= 500

Если цена ровно 100, строка попадёт в результат.
Если цена ровно 500, тоже попадёт.

BETWEEN часто используют с числами и датами.

SELECT id, amount, created_at
FROM orders
WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31';

Этот запрос выбирает заказы за период от 2024-01-01 до 2024-12-31 включительно.

Важный нюанс с датами и BETWEEN

Если колонка хранит не просто дату, а дату со временем, с верхней границей нужно быть осторожным.

Например, в created_at лежат значения такого вида:

created_at
2024-12-31 10:15:00
2024-12-31 23:59:59
2025-01-01 00:00:00

Условие:

WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31'

может не захватить весь день 2024-12-31, если база приводит правую границу к началу дня.

Для дат со временем часто пишут так:

SELECT id, amount, created_at
FROM orders
WHERE created_at >= '2024-01-01'
  AND created_at < '2025-01-01';

Это хороший и безопасный стиль для диапазонов по времени:

  • левая граница включается;
  • правая граница не включается;
  • весь 2024 год попадает в результат.

LIKE: поиск по шаблону

LIKE используют для поиска по тексту, когда нужно не точное совпадение, а шаблон.

Например, найти пользователей с почтой на Gmail:

SELECT id, email
FROM users
WHERE email LIKE '%@gmail.com';

Символ % означает «любое количество любых символов».

То есть шаблон '%@gmail.com' подходит для:

email
alice@gmail.com
bob@gmail.com
support.team@gmail.com

Ещё примеры:

SELECT id, name
FROM users
WHERE name LIKE 'A%';

Имена, которые начинаются на A.

SELECT id, name
FROM users
WHERE name LIKE '%ann%';

Имена, где внутри есть ann.

Спецсимволы в LIKE

У LIKE есть два основных спецсимвола.

Символ Значение
% любое количество любых символов
_ ровно один любой символ

Пример с _:

SELECT code
FROM products
WHERE code LIKE 'A_1';

Такой шаблон подойдёт для:

code
AA1
AB1
A91

Но не подойдёт для:

code
A100
A1
B11

Потому что _ — это ровно один символ.

Регистр в LIKE

Во многих базах сравнение строк зависит от регистра.

Например:

SELECT id, name
FROM users
WHERE name LIKE 'a%';

может найти alice, но не найти Alice.

Если нужен поиск без учёта регистра, есть несколько вариантов.

В PostgreSQL можно использовать ILIKE:

SELECT id, name
FROM users
WHERE name ILIKE 'a%';

А более универсальный вариант — привести обе стороны к одному регистру:

SELECT id, name
FROM users
WHERE LOWER(name) LIKE 'a%';

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

IS NULL: проверка на отсутствие значения

NULL — одна из главных ловушек для новичков.

NULL в SQL означает не ноль, не пустую строку и не слово NULL.
Это отсутствие значения.

Например, у пользователя может быть не заполнена дата удаления:

id name deleted_at
1 Anna NULL
2 Bob 2024-05-10
3 Vera NULL

Если нужно найти неудалённых пользователей, нельзя писать так:

SELECT id, name
FROM users
WHERE deleted_at = NULL;

Это неправильная проверка.

Для NULL используют специальный синтаксис:

SELECT id, name
FROM users
WHERE deleted_at IS NULL;

Результат:

id name
1 Anna
3 Vera

А если нужно найти строки, где значение есть:

SELECT id, name, deleted_at
FROM users
WHERE deleted_at IS NOT NULL;

Результат:

id name deleted_at
2 Bob 2024-05-10

Правило простое:

для NULL нельзя использовать = и <>. Нужны IS NULL и IS NOT NULL.

Почему NULL так странно себя ведёт

На бытовом уровне NULL можно понимать как «неизвестно».

Если значение неизвестно, то сравнение тоже становится неизвестным.

Например:

WHERE deleted_at = NULL

База не думает: «ага, оба значения пустые, значит равно».
Она думает: «значение неизвестно, сравнение тоже неизвестно».

А WHERE пропускает только те строки, где условие стало TRUE.

Если результат условия FALSE или UNKNOWN, строка не попадает в выдачу.

Поэтому проверка на NULL вынесена в отдельные операторы.

Большой пример: фильтруем заказы

Есть таблица orders.

id user_id amount status country
1 10 500 paid Russia
2 11 1500 paid USA
3 12 200 cancelled Russia
4 13 3000 paid Russia
5 14 800 pending Russia
6 15 4500 paid Belarus

Задача: найти оплаченные заказы из России на сумму больше 1000.

SELECT id, amount
FROM orders
WHERE status = 'paid'
  AND country = 'Russia'
  AND amount > 1000;

Результат:

id amount
4 3000

Почему остался только заказ 4?

id Почему не подошёл
1 сумма 500, а нужно больше 1000
2 страна USA, а нужна Russia
3 статус cancelled, а нужен paid
5 статус pending, а нужен paid
6 страна Belarus, а нужна Russia

С AND должны выполниться все условия сразу. У заказа 4 совпало всё: статус, страна и сумма.

Та же таблица, но с OR

Теперь посмотрим, как сильно меняется результат, если вместо AND использовать OR.

SELECT id, amount, country, status
FROM orders
WHERE status = 'paid'
   OR country = 'Russia'
   OR amount > 1000;

Результат:

id amount country status
1 500 Russia paid
2 1500 USA paid
3 200 Russia cancelled
4 3000 Russia paid
5 800 Russia pending
6 4500 Belarus paid

Попали все шесть строк.

Почему? Потому что для OR достаточно хотя бы одного истинного условия:

  • заказ 1 подходит по статусу и стране;
  • заказ 2 подходит по статусу и сумме;
  • заказ 3 подходит по стране;
  • заказ 4 подходит по всем условиям;
  • заказ 5 подходит по стране;
  • заказ 6 подходит по статусу и сумме.

Вот почему важно не путать AND и OR. Они могут дать совершенно разный результат на одних и тех же данных.

Пример с датами и email

Есть таблица orders.

id created_at email amount
1 2024-03-10 anna@gmail.com 500
2 2024-06-22 bob@yandex.ru 1500
3 2024-11-05 vera@gmail.com 200
4 2025-01-15 grisha@mail.ru 3000

Задача: найти заказы за 2024 год от пользователей с почтой на Gmail.

SELECT id, email, amount
FROM orders
WHERE created_at >= '2024-01-01'
  AND created_at < '2025-01-01'
  AND email LIKE '%@gmail.com';

Результат:

id email amount
1 anna@gmail.com 500
3 vera@gmail.com 200

Заказ 2 не подошёл, потому что email не на Gmail.
Заказ 4 не подошёл, потому что он создан в 2025 году.

WHERE используется не только в SELECT

Чаще всего WHERE изучают вместе с SELECT, но он нужен не только для чтения.

WHERE также используется в UPDATE и DELETE.

Например, изменить тариф только одному пользователю:

UPDATE users
SET tier = 'gold'
WHERE id = 1;

Удалить только отменённые заказы:

DELETE FROM orders
WHERE status = 'cancelled';

Вот почему важно хорошо понимать WHERE.

В SELECT ошибка просто покажет не те строки.
В UPDATE ошибка может изменить не те строки.
В DELETE ошибка может удалить не те строки.

Особенно опасны запросы без WHERE.

UPDATE users
SET tier = 'gold';

Такой запрос обновит всех пользователей.

DELETE FROM orders;

Такой запрос удалит все строки из orders.

Поэтому перед важными UPDATE и DELETE полезно сначала сделать проверочный SELECT с тем же условием.

SELECT id, email, tier
FROM users
WHERE id = 1;

Сначала посмотрели, потом изменили.

WHERE и порядок выполнения запроса

Новичку полезно понимать, что WHERE работает до группировки и до финального вывода результата.

Например:

SELECT country, COUNT(*) AS users_count
FROM users
WHERE is_active = TRUE
GROUP BY country;

Здесь база сначала оставит только активных пользователей, а уже потом сгруппирует их по стране.

Но если нужно фильтровать не обычные строки, а результат агрегации, нужен не WHERE, а HAVING.

Неправильно:

SELECT country, COUNT(*) AS users_count
FROM users
GROUP BY country
WHERE COUNT(*) > 100;

Правильно:

SELECT country, COUNT(*) AS users_count
FROM users
GROUP BY country
HAVING COUNT(*) > 100;

Запомни так:

  • WHERE фильтрует строки до группировки;
  • HAVING фильтрует группы после группировки.

Частые ошибки новичков

Сравнивают NULL через =

Неправильно:

SELECT id, name
FROM users
WHERE deleted_at = NULL;

Правильно:

SELECT id, name
FROM users
WHERE deleted_at IS NULL;

Для отсутствующих значений нужны IS NULL и IS NOT NULL.

Путают одинарные и двойные кавычки

Строки и даты пишутся в одинарных кавычках.

Правильно:

SELECT id, name
FROM users
WHERE name = 'Alice';

Неправильно:

SELECT id, name
FROM users
WHERE name = "Alice";

В PostgreSQL двойные кавычки используются для имён таблиц и колонок. Поэтому база может решить, что "Alice" — это имя колонки.

Забывают оператор между условиями

Нельзя просто поставить два условия рядом.

Неправильно:

SELECT id, name
FROM users
WHERE country = 'Russia' age > 21;

Правильно:

SELECT id, name
FROM users
WHERE country = 'Russia' AND age > 21;

Между условиями должен быть AND или OR.

Путают AND и OR

AND сужает выборку: должны выполниться все условия.
OR расширяет выборку: достаточно хотя бы одного условия.

Если результат неожиданно стал слишком большим, проверь, не поставил ли ты OR вместо AND.

Не ставят скобки в сложной логике

Плохо читается:

SELECT id, name
FROM users
WHERE country = 'Russia' AND tier = 'gold' OR age >= 30;

Лучше явно:

SELECT id, name
FROM users
WHERE (country = 'Russia' AND tier = 'gold')
   OR age >= 30;

Или так, если смысл другой:

SELECT id, name
FROM users
WHERE country = 'Russia'
  AND (tier = 'gold' OR age >= 30);

Скобки показывают намерение. Это особенно важно в рабочих запросах.

Пытаются фильтровать агрегаты через WHERE

Неправильно:

SELECT country, COUNT(*) AS users_count
FROM users
GROUP BY country
WHERE COUNT(*) > 100;

Правильно:

SELECT country, COUNT(*) AS users_count
FROM users
GROUP BY country
HAVING COUNT(*) > 100;

WHERE не знает результат COUNT(*), потому что он появляется позже.

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

SELECT name, price
FROM products
WHERE price BETWEEN 100 AND 500;

Этот запрос вернёт товары с ценой 100 и 500 тоже.

Если границы должны быть строгими, пиши явно:

SELECT name, price
FROM products
WHERE price > 100 AND price < 500;

Ожидают поиск без учёта регистра

В большинстве случаев строки с разным регистром могут считаться разными.

SELECT id, name
FROM users
WHERE name = 'alice';

Такой запрос может не найти Alice.

Если регистр не важен, можно привести обе стороны к нижнему регистру:

SELECT id, name
FROM users
WHERE LOWER(name) = LOWER('Alice');

В PostgreSQL для шаблонов также есть ILIKE.

SELECT id, name
FROM users
WHERE name ILIKE 'a%';

Пишут слишком широкий WHERE в UPDATE или DELETE

Например:

DELETE FROM orders
WHERE status <> 'paid';

Формально запрос правильный, но он может удалить слишком много: отменённые, новые, ожидающие оплаты, ошибочные — все заказы не в статусе paid.

Перед такими запросами лучше сначала выполнить:

SELECT id, status
FROM orders
WHERE status <> 'paid';

Сначала увидеть строки, потом удалять или обновлять.

Полезная привычка: читать WHERE как обычную фразу

SQL легче изучать, если читать условия по-человечески.

SELECT id, amount
FROM orders
WHERE status = 'paid'
  AND amount > 1000;

Это можно прочитать так:

Покажи id и amount из заказов, где статус оплачен и сумма больше 1000.

А вот так:

SELECT id, email
FROM users
WHERE email LIKE '%@gmail.com'
  AND deleted_at IS NULL;

читается как:

Покажи пользователей с Gmail-почтой, которые не удалены.

Если условие сложно прочитать вслух, часто его стоит переписать аккуратнее: добавить переносы строк, скобки или разбить задачу на несколько шагов.

Короткая шпаргалка

Задача Пример
Равно WHERE status = 'paid'
Не равно WHERE status <> 'cancelled'
Больше WHERE amount > 1000
Меньше или равно WHERE age <= 18
Несколько условий сразу WHERE country = 'Russia' AND age >= 21
Хотя бы одно условие WHERE status = 'paid' OR status = 'shipped'
Значение в списке WHERE country IN ('Russia', 'Belarus')
Значение не в списке WHERE status NOT IN ('cancelled', 'failed')
Диапазон включительно WHERE price BETWEEN 100 AND 500
Поиск по шаблону WHERE email LIKE '%@gmail.com'
Значение отсутствует WHERE deleted_at IS NULL
Значение есть WHERE deleted_at IS NOT NULL

Мини-резюме

WHERE — это фильтр строк в SQL.

Он отвечает на вопрос: какие строки оставить?

WHERE используют в SELECT, UPDATE и DELETE. В запросах на чтение он помогает получить только нужные данные. В запросах на изменение он защищает от случайного обновления или удаления всей таблицы.

Внутри WHERE можно писать:

  • сравнения через =, <>, >, <, >=, <=;
  • логические условия через AND, OR, NOT;
  • проверки по списку через IN;
  • диапазоны через BETWEEN;
  • поиск по шаблону через LIKE;
  • проверки пустых значений через IS NULL и IS NOT NULL.

Главные правила для новичка:

  • AND требует выполнения всех условий;
  • OR требует хотя бы одного условия;
  • BETWEEN включает обе границы;
  • NULL нельзя проверять через =;
  • в сложных условиях лучше ставить скобки;
  • перед опасным UPDATE или DELETE сначала сделай SELECT с тем же WHERE.

WHERE — это не просто часть синтаксиса. Это умение задавать базе точный вопрос. Чем точнее вопрос, тем чище, быстрее и понятнее будет ответ.

Похожие статьи

Закрепи на практике

Решай задачи в SQL-тренажёре с мгновенной проверкой и подсказками.

Открыть тренажёр