Оператор WHERE: фильтрация данных в SQL
Оператор WHERE в SQL задает условие, по которому из таблицы отбираются только нужные строки: сотрудники одного отдела, заказы за месяц, товары дороже заданной цены. Ниже разобраны синтаксис, операторы сравнения и логики, BETWEEN, IN, LIKE и IS NULL, использование WHERE в UPDATE и DELETE, а также безопасная подстановка значений из Python.

Содержание статьи
Синтаксис WHERE
Условие пишется после FROM и перед GROUP BY и ORDER BY. СУБД проверяет его для каждой строки таблицы: если выражение истинно, строка попадает в результат, если ложно или равно NULL, отбрасывается.
SELECT name, salary
FROM employees
WHERE department = 'IT';
Логический порядок выполнения запроса отличается от порядка записи: сначала FROM выбирает таблицу, потом WHERE фильтрует строки, затем GROUP BY группирует, а SELECT формирует столбцы. Поэтому в WHERE нельзя использовать агрегатные функции вроде COUNT() и SUM(). Основы выборки описаны в статье об операторе SELECT.
Все примеры ниже относятся к таблице employees со столбцами id, name, department, salary, hired (дата приема в формате ГГГГ-ММ-ДД) и email.
Операторы сравнения
Простейшее условие сравнивает столбец со значением или с другим столбцом. Строки и даты берут в одинарные кавычки, числа пишут без кавычек.
| Оператор | Смысл | Пример |
|---|---|---|
| = | Равно | department = 'IT' |
| <> или != | Не равно | department <> 'HR' |
| >, < | Больше, меньше | salary > 50000 |
| >=, <= | Больше или равно, меньше или равно | hired >= '2024-01-01' |
Даты в SQLite хранятся строками, и формат ГГГГ-ММ-ДД сравнивается правильно как обычный текст. Если хранить даты в виде ДД.ММ.ГГГГ, сравнение больше-меньше даст неверный результат.
SELECT name, hired
FROM employees
WHERE hired >= '2024-01-01';
Логические операторы AND, OR и NOT
Несколько условий объединяют логическими операторами. AND требует выполнения всех условий, OR хотя бы одного, NOT инвертирует условие.
SELECT name, department, salary
FROM employees
WHERE department = 'IT' AND salary > 50000;
У операторов есть приоритет: сначала NOT, затем AND, последним OR. Из-за этого запрос ниже без скобок вернет всех сотрудников отдела продаж, даже с маленькой зарплатой, потому что AND связал только второе условие с третьим.
-- ошибка: читается как IT OR (Sales AND salary > 70000)
SELECT * FROM employees
WHERE department = 'IT' OR department = 'Sales' AND salary > 70000;
-- верно
SELECT * FROM employees
WHERE (department = 'IT' OR department = 'Sales') AND salary > 70000;
Правило простое: если в условии встречаются и AND, и OR, ставьте скобки, даже когда приоритет совпадает с задуманным. Так запрос проще читать.
Специальные условия
Для типовых проверок в SQL есть короткие операторы, которые заменяют громоздкие цепочки сравнений.
BETWEEN для диапазона
BETWEEN проверяет попадание значения в диапазон, причем обе границы включаются. Запись salary BETWEEN 40000 AND 60000 равносильна salary >= 40000 AND salary <= 60000.
SELECT name, hired
FROM employees
WHERE hired BETWEEN '2025-01-01' AND '2025-12-31';
IN для списка значений
IN заменяет несколько условий через OR по одному столбцу. NOT IN выбирает строки, значение которых не входит в список.
SELECT name, department
FROM employees
WHERE department IN ('IT', 'Sales', 'Support');
Будьте осторожны с NOT IN, если в списке или подзапросе может оказаться NULL: тогда условие никогда не станет истинным и запрос вернет пустой результат.
LIKE для поиска по шаблону
LIKE сравнивает строку с шаблоном. Знак % заменяет любое количество символов, включая ноль, знак _ ровно один символ.
SELECT name, email FROM employees
WHERE email LIKE '%@gmail.com'; -- оканчивается на @gmail.com
SELECT name FROM employees
WHERE name LIKE 'Ан_'; -- три буквы, начинается на Ан
В SQLite LIKE по умолчанию не различает регистр только для латинских букв. Для кириллицы 'иван%' не найдет строку 'Иван', поэтому для русских текстов приводите регистр в Python или храните отдельный столбец в нижнем регистре.
IS NULL для пустых значений
NULL означает отсутствие значения, и любое сравнение с ним дает не истину и не ложь, а NULL. Поэтому email = NULL никогда не сработает, нужно писать IS NULL или IS NOT NULL.
SELECT name FROM employees
WHERE email IS NULL;
WHERE в UPDATE и DELETE
WHERE работает не только при выборке. В командах UPDATE и DELETE он определяет, какие строки будут изменены или удалены. Запрос без WHERE затронет всю таблицу, и это одна из самых дорогих ошибок в работе с базами.
UPDATE employees
SET salary = salary * 1.1
WHERE department = 'Support';
DELETE FROM employees
WHERE hired < '2015-01-01' AND department = 'Archive';
Перед удалением полезно выполнить SELECT с тем же условием и убедиться, что выбраны нужные строки. Примеры удаления из Python есть в статье о выборке и удалении в SQLite.
Условие WHERE в запросах из Python
В модуле sqlite3 значения для условия никогда не вставляют в текст запроса через f-строку или конкатенацию: это открывает дорогу SQL-инъекциям и ломается на кавычках в данных. Вместо значений ставят знаки ?, а сами значения передают вторым аргументом кортежем.
import sqlite3
with sqlite3.connect('company.db') as conn:
cur = conn.execute(
'SELECT name, salary FROM employees '
'WHERE department = ? AND salary >= ?',
('IT', 50000),
)
for name, salary in cur.fetchall():
print(name, salary)
Для IN с переменным числом значений знаки вопроса генерируют по длине списка:
departments = ['IT', 'Sales']
marks = ', '.join('?' * len(departments))
sql = f'SELECT name FROM employees WHERE department IN ({marks})'
rows = conn.execute(sql, departments).fetchall()
Здесь f-строка подставляет только знаки вопроса, а не данные, поэтому запрос остается безопасным. Описание параметров есть в документации sqlite3.
На скорость фильтрации сильно влияет индекс: если по столбцу из WHERE часто ищут, создайте его командой CREATE INDEX idx_dep ON employees(department). Без индекса СУБД просматривает всю таблицу построчно.
Частые вопросы
Ответы на вопросы, которые часто возникают при составлении условий.
Чем WHERE отличается от HAVING?
WHERE фильтрует отдельные строки до группировки, HAVING фильтрует уже готовые группы после GROUP BY и может использовать агрегатные функции. Подробнее о группировке в статье про агрегатные функции SQL.
Можно ли использовать в WHERE несколько таблиц?
Да, если таблицы соединены через JOIN или перечислены в FROM. Столбцы тогда указывают с именем таблицы: orders.amount > 1000.
Где в запросе ставить ORDER BY относительно WHERE?
Строго после WHERE (и после GROUP BY с HAVING, если они есть). Сначала строки отбираются, затем сортируются.
Почему условие column = NULL ничего не находит?
Сравнение с NULL через знак равенства всегда дает NULL, а такие строки в результат не попадают. Для проверки пустых значений используйте IS NULL.