WHERE и операторы сравнения
WHERE - это фильтр. Без него ты просишь базу: «дай всё». А потом удивляешься, что «всё» - это 3 миллиона строк. Сам по себе WHERE строки не ускоряет: если по колонке нет индекса, база всё равно пролистает таблицу целиком.
Простой WHERE
SELECT id, name FROM users
WHERE id = 42;
SELECT * FROM orders
WHERE total > 1000;
Операторы
<ComparisonTable data={ headers: ["Оператор", "Смысл", "Пример"], rows: [ ["=", "равно", "id = 10"], ["<>", "не равно", "role <> 'admin'"], [">, <, >=, <=", "сравнение", "age >= 18"], ["IN (...)", "в наборе", "status IN ('new','paid')"], ["BETWEEN", "в диапазоне", "age BETWEEN 18 AND 65"], ["LIKE", "по шаблону", "email LIKE '%@gmail.com'"], ["IS NULL", "пусто", "deleted_at IS NULL"], ["NOT", "отрицание", "NOT (age < 18)"] ], } />
IN - проверка в наборе
-- Вместо: WHERE status = 'new' OR status = 'paid' OR status = 'pending'
SELECT * FROM orders
WHERE status IN ('new', 'paid', 'pending');
-- С числами тоже работает
SELECT * FROM users
WHERE id IN (1, 5, 10, 42);
BETWEEN - диапазон
-- Все люди от 18 до 65
SELECT * FROM users
WHERE age BETWEEN 18 AND 65;
-- То же самое без BETWEEN:
-- WHERE age >= 18 AND age <= 65
-- С датами
SELECT * FROM orders
WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31';
LIKE - поиск по шаблону
% = любое количество символов
_ = ровно один символ
-- Email на @gmail.com
SELECT * FROM users WHERE email LIKE '%@gmail.com';
-- Имя начинается с 'А'
SELECT * FROM users WHERE name LIKE 'A%';
-- Имя заканчивается на 'а'
SELECT * FROM users WHERE name LIKE '%a';
-- Номер телефона вида +7 что-то что-то
SELECT * FROM users WHERE phone LIKE '+7 _ _';
-- Поиск слова в середине (скажем, 'sql' в любом месте в названии курса)
SELECT * FROM courses WHERE title LIKE '%SQL%';
NOT - отрицание
-- Все, кроме админов
SELECT * FROM users WHERE NOT role = 'admin';
-- или короче:
SELECT * FROM users WHERE role <> 'admin';
-- Все, кроме определённых статусов
SELECT * FROM orders WHERE status NOT IN ('canceled', 'failed');
-- Все с заполненным email (не NULL)
SELECT * FROM users WHERE NOT email IS NULL;
-- или проще:
SELECT * FROM users WHERE email IS NOT NULL;
-- Не совпадает с шаблоном
SELECT * FROM users WHERE email NOT LIKE '%@gmail.com';
-- Не в диапазоне
SELECT * FROM users WHERE age NOT BETWEEN 18 AND 65;
NULL - коварное значение
NULL мы уже видели в результатах SELECT - там он просто «пусто». В условиях он ведёт себя куда коварнее.
ВАЖНО: WHERE x = NULL не работает!
-- НЕПРАВИЛЬНО:
SELECT * FROM users WHERE phone = NULL; - Вернёт 0 строк!
-- ПРАВИЛЬНО:
SELECT * FROM users WHERE phone IS NULL;
SELECT * FROM users WHERE email IS NOT NULL;
NULL заразителен в логике:
-- Если email IS NULL, условие (email = 'test@mail.com') дает NULL, не false
SELECT * FROM users WHERE email = 'test@mail.com';
-- Не вернёт строку, даже если там NULL!
AND / OR и приоритет операций
AND имеет выше приоритет чем OR. Поэтому:
-- Читается как: (role = 'admin' AND age > 30) OR status = 'vip'
SELECT * FROM users
WHERE role = 'admin' AND age > 30 OR status = 'vip';
-- Если хочешь другое: (role = 'admin') AND (age > 30 OR status = 'vip')
SELECT * FROM users
WHERE role = 'admin' AND (age > 30 OR status = 'vip');
Важно помнить: WHERE отсекает строки до группировки. Фильтровать уже посчитанные группы умеет HAVING - о нём в уроке про GROUP BY и агрегаты.
Практический пример:
-- Найди активных админов или VIP пользователей
SELECT * FROM users
WHERE (role = 'admin' OR role = 'vip')
AND deleted_at IS NULL
AND status = 'active';
Условие deleted_at IS NULL - это soft delete: строку не удаляют физически, а помечают датой. Как это устроено целиком, смотри в мини-проекте трека.
Мини-задание
- Найди пользователей с email на
@gmail.com(LIKE) - Выведи заказы со статусом
new,in_progressилиpending(IN) - Получи людей возрастом 25-40 лет (BETWEEN)
- Найди пользователей БЕЗ телефона (NOT, IS NULL)
- Выведи заказы на сумму > 1000, но БЕЗ статуса 'canceled' (AND, NOT IN)