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;
База рассуждает примерно так:
- Берёт первую строку.
- Смотрит значение
age.
- Проверяет условие
age > 18.
- Если условие истинно — строка попадает в результат.
- Если условие ложно — строка отбрасывается.
- Переходит к следующей строке.
То есть 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;
Результат:
Почему?
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' подходит для:
Ещё примеры:
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';
Такой шаблон подойдёт для:
Но не подойдёт для:
Потому что _ — это ровно один символ.
Регистр в 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;
Результат:
А если нужно найти строки, где значение есть:
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;
Результат:
Почему остался только заказ 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.
Задача: найти заказы за 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';
Результат:
Заказ 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 — это не просто часть синтаксиса. Это умение задавать базе точный вопрос. Чем точнее вопрос, тем чище, быстрее и понятнее будет ответ.
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;База рассуждает примерно так:
age.age > 18.То есть
WHERE— это проверка «подходит строка или нет».Важно:
WHEREфильтрует строки, аSELECTвыбирает колонки.SELECT name, age FROM users WHERE age > 18;Здесь:
SELECT name, ageговорит, какие колонки показать;FROM usersговорит, из какой таблицы брать данные;WHERE age > 18говорит, какие строки оставить.Первый пример с таблицей
Есть таблица
products.Нужно получить товары дороже
1000.SELECT name, price FROM products WHERE price > 1000;Результат:
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;Читается так:
Есть таблица
users.Запрос:
SELECT name FROM users WHERE country = 'Russia' AND age >= 21;Результат:
Почему?
Annaподходит: странаRussia, возраст25.Bobне подходит: возраст подходит, но странаUSA.Veraне подходит: страна подходит, но возраст17.Grigoryподходит: странаRussia, возраст40.Для
ANDнужно, чтобы совпало всё.OR: когда достаточно одного условия
ORозначает «или».Строка попадёт в результат, если истинно хотя бы одно условие.
Возьмём ту же таблицу:
Запрос:
SELECT name FROM users WHERE country = 'Russia' OR age >= 21;Результат:
Теперь попали все:
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);Читается так:
Скобки помогают человеку сразу увидеть логику.
Без скобок 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лежат значения такого вида:Условие:
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';Это хороший и безопасный стиль для диапазонов по времени:
LIKE: поиск по шаблону
LIKEиспользуют для поиска по тексту, когда нужно не точное совпадение, а шаблон.Например, найти пользователей с почтой на Gmail:
SELECT id, email FROM users WHERE email LIKE '%@gmail.com';Символ
%означает «любое количество любых символов».То есть шаблон
'%@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';Такой шаблон подойдёт для:
Но не подойдёт для:
Потому что
_— это ровно один символ.Регистр в 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.Это отсутствие значения.
Например, у пользователя может быть не заполнена дата удаления:
Если нужно найти неудалённых пользователей, нельзя писать так:
SELECT id, name FROM users WHERE deleted_at = NULL;Это неправильная проверка.
Для
NULLиспользуют специальный синтаксис:SELECT id, name FROM users WHERE deleted_at IS NULL;Результат:
А если нужно найти строки, где значение есть:
SELECT id, name, deleted_at FROM users WHERE deleted_at IS NOT NULL;Результат:
Правило простое:
для
NULLнельзя использовать=и<>. НужныIS NULLиIS NOT NULL.Почему NULL так странно себя ведёт
На бытовом уровне
NULLможно понимать как «неизвестно».Если значение неизвестно, то сравнение тоже становится неизвестным.
Например:
WHERE deleted_at = NULLБаза не думает: «ага, оба значения пустые, значит равно».
Она думает: «значение неизвестно, сравнение тоже неизвестно».
А
WHEREпропускает только те строки, где условие сталоTRUE.Если результат условия
FALSEилиUNKNOWN, строка не попадает в выдачу.Поэтому проверка на
NULLвынесена в отдельные операторы.Большой пример: фильтруем заказы
Есть таблица
orders.Задача: найти оплаченные заказы из России на сумму больше
1000.SELECT id, amount FROM orders WHERE status = 'paid' AND country = 'Russia' AND amount > 1000;Результат:
Почему остался только заказ
4?500, а нужно больше1000USA, а нужнаRussiacancelled, а нуженpaidpending, а нуженpaidBelarus, а нужнаRussiaС
ANDдолжны выполниться все условия сразу. У заказа4совпало всё: статус, страна и сумма.Та же таблица, но с OR
Теперь посмотрим, как сильно меняется результат, если вместо
ANDиспользоватьOR.SELECT id, amount, country, status FROM orders WHERE status = 'paid' OR country = 'Russia' OR amount > 1000;Результат:
Попали все шесть строк.
Почему? Потому что для
ORдостаточно хотя бы одного истинного условия:1подходит по статусу и стране;2подходит по статусу и сумме;3подходит по стране;4подходит по всем условиям;5подходит по стране;6подходит по статусу и сумме.Вот почему важно не путать
ANDиOR. Они могут дать совершенно разный результат на одних и тех же данных.Пример с датами и email
Есть таблица
orders.Задача: найти заказы за 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';Результат:
Заказ
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;Это можно прочитать так:
А вот так:
SELECT id, email FROM users WHERE email LIKE '%@gmail.com' AND deleted_at IS NULL;читается как:
Если условие сложно прочитать вслух, часто его стоит переписать аккуратнее: добавить переносы строк, скобки или разбить задачу на несколько шагов.
Короткая шпаргалка
WHERE status = 'paid'WHERE status <> 'cancelled'WHERE amount > 1000WHERE age <= 18WHERE country = 'Russia' AND age >= 21WHERE status = 'paid' OR status = 'shipped'WHERE country IN ('Russia', 'Belarus')WHERE status NOT IN ('cancelled', 'failed')WHERE price BETWEEN 100 AND 500WHERE email LIKE '%@gmail.com'WHERE deleted_at IS NULLWHERE 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— это не просто часть синтаксиса. Это умение задавать базе точный вопрос. Чем точнее вопрос, тем чище, быстрее и понятнее будет ответ.