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');
Если у тебя `AND` и `OR` вместе - ставь скобки явно. Лучше перестраховаться, чем ловить баг час.

Важно помнить: 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)

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