LIKE и шаблоны (% и _)

LIKE и шаблоны (% и _)

В третьем модуле вы освоили все базовые инструменты фильтрации: WHERE, логические операторы, сортировку, ограничение результата. Оператор = отлично работает, когда вы знаете точное значение — WHERE city = 'Москва'. Но что если нужно найти всех клиентов, чьё имя начинается с «Ан»? Или все email-адреса на домене @gmail.com? Или продукты, в названии которых есть слово «ноутбук» независимо от регистра? Для поиска по шаблону в SQL существует оператор LIKE.

Что такое LIKE

LIKE — это оператор сравнения строк, который поддерживает шаблоны (wildcards). В отличие от =, который требует точного совпадения, LIKE позволяет искать строки, содержащие определённые подстроки, начинающиеся или заканчивающиеся определённым образом.

Базовый синтаксис:

SELECT колонки
FROM   таблица
WHERE  колонка LIKE 'шаблон';

Метасимвол «%»: любое количество символов

Символ % в шаблоне означает «любое количество любых символов (включая ноль)». Это самый используемый метасимвол в LIKE.

Примеры:

-- Все строки, начинающиеся с 'Ан'
WHERE name LIKE 'Ан%'   -- найдёт: Анна, Антон, Андрей, Анастасия

-- Все строки, заканчивающиеся на 'ов'
WHERE name LIKE '%ов'   -- найдёт: Иванов, Петров, Кузнецов

-- Все строки, содержащие 'sql' в любом месте
WHERE description LIKE '%sql%'  -- найдёт: "Введение в SQL", "MySQL tutorial", "PostgreSQL docs"

Таблица products:

id | name
---+---------------------------
1  | Ноутбук HP ProBook
2  | Ноутбук Lenovo IdeaPad
3  | Мышь Logitech
4  | Монитор Samsung
5  | Клавиатура механическая

Запрос:

SELECT name FROM products WHERE name LIKE 'Ноутбук%';

Результат: «Ноутбук HP ProBook» и «Ноутбук Lenovo IdeaPad». Остальные строки не начинаются с «Ноутбук».

Проверь себя: сколько строк из таблицы выше вернёт WHERE name LIKE '%а%'?

Метасимвол «_»: ровно один символ

Символ _ (подчёркивание) означает ровно один любой символ. Это полезно, когда вы знаете длину строки или позицию нужного символа.

-- Артикулы вида A-001, B-002, C-003 (одна буква, дефис, три цифры)
WHERE article LIKE '_-___'

-- Телефоны в формате +7-XXX-XXX-XX-XX (подсчитайте символы)
WHERE phone LIKE '+7-___-___-__-__'

Практический пример — найти все коды продуктов, которые начинаются с «P» и имеют ровно 4 символа:

SELECT code, name FROM products WHERE code LIKE 'P___';
-- Вернёт: P001, P123, PABC, но не P01 или P00123

Сочетание % и _ даёт гибкий поиск:

-- Строки, где вторая буква — 'а'
WHERE name LIKE '_а%'  -- Мария, Налог, Санкт-Петербург, Дана

LIKE чувствителен к регистру

По умолчанию LIKE в PostgreSQL чувствителен к регистру:

WHERE name LIKE 'ноутбук%'  -- не найдёт 'Ноутбук HP ProBook'
WHERE name LIKE 'Ноутбук%'  -- найдёт

Для поиска без учёта регистра используется оператор ILIKE (регистронезависимый LIKE, специфичный для PostgreSQL):

WHERE name ILIKE 'ноутбук%'  -- найдёт и 'Ноутбук', и 'ноутбук', и 'НОУТБУК'

Альтернатива, работающая в любой СУБД — LOWER():

WHERE LOWER(name) LIKE 'ноутбук%'  -- приводим колонку к нижнему регистру

В SQLite LIKE по умолчанию нечувствителен к регистру для ASCII-символов, но чувствителен для символов вне ASCII (кирилличные буквы). На практике лучше явно использовать LOWER().

NOT LIKE: исключение по шаблону

NOT LIKE работает как инверсия — возвращает строки, которые не соответствуют шаблону:

-- Все товары, название которых не содержит 'Ноутбук'
SELECT name FROM products WHERE name NOT LIKE '%Ноутбук%';

Результат: Мышь Logitech, Монитор Samsung, Клавиатура механическая.

Экранирование метасимволов

Что если нужно найти строки, которые буквально содержат % или _? Например, скидку «10%» или колонку со значением «кол_во»? Эти символы нужно экранировать.

В PostgreSQL для экранирования используется обратный слеш \ или явное задание escape-символа через ESCAPE:

-- Найти строки, содержащие буквальный знак процента
WHERE discount_text LIKE '%10\%%' ESCAPE '\'

-- Или задать другой escape-символ
WHERE code LIKE '%!_%' ESCAPE '!'   -- ищем буквальное подчёркивание

На практике это редкая ситуация — когда в данных есть символы % или _, которые нужно искать буквально. Но знать о такой возможности полезно.

Производительность LIKE

LIKE с шаблоном в начале ('%keyword%') не может использовать обычный индекс — СУБД вынуждена сканировать всю таблицу. Это медленно на больших данных.

LIKE 'keyword%' (шаблон только в конце) может использовать B-tree индекс и работает быстро.

Для полнотекстового поиска PostgreSQL предлагает специальные механизмы (tsvector, tsquery, индексы GIN), но это уже за пределами базового курса.

Практический пример: поиск по базе клиентов

Задача: найти всех клиентов с email на корпоративном домене и именем, начинающимся с «А»:

SELECT name, email
FROM   customers
WHERE  email LIKE '%@company.ru'
  AND  name  LIKE 'А%';

Запрос комбинирует два LIKE-условия через AND. Строки, удовлетворяющие обоим условиям, попадают в результат.

Другой пример — поиск товаров по части артикула:

SELECT article, name, price
FROM   products
WHERE  article LIKE 'NB-%'   -- все ноутбуки (артикул начинается с NB-)
ORDER BY price ASC;

Типичные ошибки

1. Забытый % вокруг шаблона:

WHERE name LIKE 'Ноутбук'   -- то же самое, что = 'Ноутбук'
WHERE name LIKE '%Ноутбук%' -- правильно для поиска подстроки

LIKE без метасимволов эквивалентен =.

2. Путаница между % и _:

WHERE code LIKE 'P%'   -- все коды, начинающиеся с P (любой длины)
WHERE code LIKE 'P_'   -- коды ровно из 2 символов, первый P

3. Регистр в PostgreSQL:

WHERE name LIKE '%ноутбук%'  -- в PostgreSQL не найдёт 'Ноутбук HP'
WHERE name ILIKE '%ноутбук%' -- найдёт независимо от регистра

LIKE vs ILIKE vs LOWER(): что выбрать

В PostgreSQL есть три подхода к регистронезависимому поиску:

ILIKE — самое простое решение, специфичное для PostgreSQL:

WHERE name ILIKE '%ноутбук%'

LOWER() — работает в любой СУБД, включая MySQL и SQLite:

WHERE LOWER(name) LIKE '%ноутбук%'

UPPER() — то же самое, но приводит к верхнему регистру:

WHERE UPPER(name) LIKE '%НОУТБУК%'

Если ваш код должен быть переносимым между СУБД — используйте LOWER(). Если пишете только для PostgreSQL — ILIKE удобнее и нагляднее.

LIKE в реальных задачах

Вот несколько типичных сценариев, где LIKE незаменим:

Поиск по части имени в базе клиентов:

SELECT id, first_name, last_name, email
FROM   customers
WHERE  last_name ILIKE '%иванов%'   -- найдёт Иванов, Иванова, Иванович...
ORDER BY last_name;

Фильтрация URL по домену:

SELECT page_url, visits
FROM   analytics
WHERE  page_url LIKE 'https://shop.example.com/%'
ORDER BY visits DESC;

Поиск по коду SKU (Stock Keeping Unit):

SELECT sku, product_name, stock
FROM   inventory
WHERE  sku LIKE 'EL-%'    -- все SKU из категории «Электроника»
  AND  stock > 0;

Поиск дубликатов email-провайдеров:

SELECT DISTINCT
  CASE
    WHEN email LIKE '%@gmail.com'   THEN 'Gmail'
    WHEN email LIKE '%@yandex.ru'   THEN 'Яндекс'
    WHEN email LIKE '%@mail.ru'     THEN 'Mail.ru'
    ELSE 'Другое'
  END AS provider
FROM customers;

Этот пример использует CASE WHEN — мощный инструмент условных выражений, который мы подробно разберём в уроке 4-5. Сейчас воспринимайте его как «если email заканчивается на X, то верни строку Y».

Краткий итог

  • LIKE — поиск по шаблону; % — любое количество символов; _ — ровно один символ
  • LIKE 'abc%' — начинается с «abc»; LIKE '%abc' — заканчивается на «abc»; LIKE '%abc%' — содержит «abc»
  • NOT LIKE — строки, не соответствующие шаблону
  • В PostgreSQL LIKE чувствителен к регистру; ILIKE — нечувствителен; LOWER() — переносимый вариант
  • LIKE '%keyword%' не использует обычный индекс — медленно на больших данных
  • Для экранирования % и _ используйте \ или ESCAPE

Что дальше

Теперь вы умеете искать по шаблону. Следующий оператор — IN, который позволяет проверить, входит ли значение в заданный список. Это удобная альтернатива нескольким условиям через OR.

Попробуйте интерактивную версию

Практические задачи, квизы и AI-наставник — бесплатный старт без карты

Перейти к практике