LIKE в SQL проверяет, соответствует ли строка шаблону. Символ % заменяет любую последовательность символов, включая пустую, а _ — ровно один символ. Для поиска в PostgreSQL без учёта регистра используют ILIKE. Например, name ILIKE '%sql%' найдёт названия SQL guide, sql workbook и PostgreSQL handbook.
Дальше все запросы выполняются в PostgreSQL 17.9. ILIKE — расширение PostgreSQL, поэтому переносить его в другую СУБД без проверки нельзя. Правила сопоставления регистра зависят от локали; примеры с ASCII-названиями позволяют проверить механику без особенностей конкретного алфавита. Определения операторов приведены в документации PostgreSQL.
Синтаксис LIKE
Общая форма одна для всех СУБД: выражение [NOT] LIKE 'шаблон' [ESCAPE 'символ']. Выражение — колонка или строка, шаблон — строка с масками. % заменяет любую последовательность символов, в том числе пустую, _ — ровно один символ, все остальные символы шаблона должны совпасть буквально. ESCAPE задаёт символ, который отменяет специальный смысл следующего % или _. Результат — true, false или NULL, если хотя бы одна сторона неизвестна.
Проверить это можно без таблицы:
SELECT
'SQL guide' LIKE 'SQL%' AS starts_with_sql,
'SQL guide' LIKE '%guide' AS ends_with_guide,
'SQL guide' LIKE '%gu_de' AS one_symbol_gap,
'SQL guide' LIKE 'guide' AS whole_string;
Ответ: true, true, true, false. Последнее условие ложно: без % шаблон должен совпасть со всей строкой, а не с её частью.
ILIKE — вариант без учёта регистра, который есть в PostgreSQL. В MySQL, SQL Server и SQLite его нет, и регистр там работает по своим правилам — они собраны в отдельном разделе ниже.
Подготовить таблицу товаров
Выполни этот блок в учебном SQL-сеансе. Временная таблица существует только до его закрытия:
CREATE TEMP TABLE products (
id integer PRIMARY KEY,
name text
);
INSERT INTO products (id, name) VALUES
(1, 'SQL guide'),
(2, 'sql workbook'),
(3, 'PostgreSQL handbook'),
(4, 'T-shirt 100% cotton'),
(5, 'usb_c cable'),
(6, 'usb-c cable'),
(7, 'USB hub'),
(8, NULL),
(9, 'SQL');
Здесь есть разные регистры, буквальные % и _, а также неизвестное название NULL.
Знак % допускает и суффикс, и его отсутствие
LIKE 'SQL%' пропустит строки 1 и 9. Для строки с NULL результат неизвестен, поэтому она в выборку не попадёт.SQL LIKE: начало, конец и часть строки
Выберем товары, названия которых начинаются с SQL:
SELECT id, name
FROM products
WHERE name LIKE 'SQL%'
ORDER BY id;
Результат:
| id | name |
|---|---|
| 1 | SQL guide |
| 9 | SQL |
Товар SQL тоже подходит: % разрешает ноль символов. Без маски шаблон LIKE 'SQL' на нашей таблице совпадёт только с названием SQL; для обычного равенства понятнее написать name = 'SQL'.
Положение % меняет условие. Каждый шаблон из таблицы можно подставить в тот же запрос:
| Условие | Задача | Подходящие id |
|---|---|---|
name LIKE 'SQL%' | Начинается с SQL | 1, 9 |
name LIKE '%cotton' | Заканчивается на cotton | 4 |
name LIKE '%SQL%' | Содержит SQL в любой позиции | 1, 3, 9 |
name LIKE 'SQL' | Целиком совпадает с SQL | 9 |
LIKE сопоставляет всю строку. Без % по краям он не ищет фрагмент автоматически. Звёздочка * здесь тоже не заменяет %: это обычный символ, а не маска SQL LIKE.
Символ _ заменяет ровно один символ
Такой запрос найдёт два кабеля:
SELECT id, name
FROM products
WHERE name LIKE 'usb_c cable'
ORDER BY id;
| id | name |
|---|---|
| 5 | usb_c cable |
| 6 | usb-c cable |
В шаблоне _ стоит между usb и c. На его месте разрешён один символ: и подчёркивание, и дефис подходят. Поэтому это условие не проверяет буквальное имя кабеля.
Разницу между пустой последовательностью и одним символом видно в короткой проверке:
SELECT
'' LIKE '%' AS empty_matches_percent,
'' LIKE '_' AS empty_matches_underscore;
Ответ — true и false. Число _ задаёт точную длину участка; % такой длины не задаёт.
ILIKE: поиск без учёта регистра в PostgreSQL
Заменим оператор, оставив тот же префикс:
SELECT id, name
FROM products
WHERE name ILIKE 'sql%'
ORDER BY id;
| id | name |
|---|---|
| 1 | SQL guide |
| 2 | sql workbook |
| 9 | SQL |
PostgreSQL handbook не попал в ответ: слово начинается с Postgre, а шаблон требует sql в начале. Для поиска в любой позиции используй ILIKE '%sql%' — на наших данных это строки 1, 2, 3 и 9.
Для нелатинских названий проверяй поведение на локали своей базы. ILIKE не означает поиск похожих слов: он не исправляет опечатки и не делает транслитерацию.
LIKE в MySQL, SQL Server и SQLite
Маски % и _ одинаковы везде, а регистр и дополнительные возможности зависят от СУБД:
| СУБД | Регистр в LIKE | Чего нет и что есть дополнительно |
|---|---|---|
| PostgreSQL | учитывается; без учёта — ILIKE | SIMILAR TO и регулярные выражения через оператор ~ |
| MySQL | зависит от сопоставления колонки: при сопоставлениях *_ci, которые стоят по умолчанию, регистр не учитывается | ILIKE нет; учесть регистр — LIKE BINARY или сопоставление *_bin |
| SQL Server | зависит от сопоставления: у большинства по умолчанию _CI, регистр не учитывается | ILIKE нет; в шаблоне есть [абв] и [^абв] — набор или диапазон символов на одной позиции |
| SQLite | не учитывается только для латиницы ASCII: 'ABC' LIKE 'abc' даёт 1, а 'Ярд' LIKE 'ярд' — 0 | ILIKE нет; PRAGMA case_sensitive_like = 1 включает учёт регистра; GLOB ищет с масками * и ? и всегда учитывает регистр |
Переносимый способ искать без учёта регистра — привести обе стороны к одному регистру:
SELECT id, name
FROM products
WHERE lower(name) LIKE '%sql%'
ORDER BY id;
В PostgreSQL ответ тот же, что у ILIKE '%sql%': id 1, 2, 3 и 9. Приём работает во всех четырёх СУБД, но обычный индекс по колонке name при нём не используется — нужен индекс по выражению lower(name).
ESCAPE: как найти буквальные % и _
Для поиска знака процента выберем ! как escape-символ. Он отменяет специальный смысл следующего % или _:
SELECT id, name
FROM products
WHERE name LIKE '%!%%' ESCAPE '!'
ORDER BY id;
Вернётся строка 4, T-shirt 100% cotton. Шаблон читается как три части: % допускает начало, !% требует настоящий знак процента, последний % допускает конец.
Буквальное подчёркивание ищется аналогично:
SELECT id, name
FROM products
WHERE name LIKE '%!_%' ESCAPE '!'
ORDER BY id;
Теперь подходит только строка 5, usb_c cable. Сам escape-символ тоже нужно экранировать: !! означает один !.
SELECT 'wow!' LIKE '%!!' ESCAPE '!' AS ends_with_exclamation;
Результат — true. Явный ESCAPE '!' помогает не путать экранирование шаблона с обратными слешами в строках SQL и языка приложения.
NOT LIKE и NULL: почему пропал товар без названия
Запрос «всё, что не начинается с SQL»:
SELECT id, name
FROM products
WHERE name NOT LIKE 'SQL%'
ORDER BY id;
Он вернёт id 2, 3, 4, 5, 6 и 7. Строки 8 нет: сравнение неизвестного названия с шаблоном даёт NULL, а отрицание неизвестности не превращает её в true.
Если товары без названия тоже должны входить в результат, назови это условие явно:
SELECT id, name
FROM products
WHERE name NOT ILIKE '%sql%' OR name IS NULL
ORDER BY id;
Ответ содержит id 4, 5, 6, 7 и 8. Обработка отсутствующих значений и оператор IS NULL описаны в документации PostgreSQL. Более подробно трёхзначная логика разобрана в статье про NULL.
Как передать поисковую строку из приложения
Не вставляй пользовательский ввод внутрь SQL через конкатенацию. Передавай целый шаблон параметром. Механизм можно проверить прямо в PostgreSQL:
PREPARE find_products(text) AS
SELECT id, name
FROM products
WHERE name ILIKE $1 ESCAPE '!'
ORDER BY id;
EXECUTE find_products('%sql%');
EXECUTE find_products('%!_%');
DEALLOCATE find_products;
Первое выполнение вернёт id 1, 2, 3 и 9, второе — id 5. $1 обозначает значение параметра, а не часть текста запроса. В драйвере приложения синтаксис заполнителя может быть другим; механизм PREPARE описан в справочнике PostgreSQL.
Параметризация защищает структуру SQL, но не отключает маски. Если пользователь ввёл %, параметр со значением %%% всё ещё найдёт любое известное название. Для буквального поиска сначала замени в пользовательском тексте ! на !!, затем % на !%, _ на !_ и только после этого добавь % с двух сторон. Для ввода usb_c получится %usb!_c%. Если интерфейс намеренно разрешает пользователю маски, такое экранирование, наоборот, меняет согласованное поведение поиска.
Почему индекс не всегда ускоряет LIKE
Для префикса LIKE 'SQL%' PostgreSQL может использовать B-tree; при локали, отличной от C, может понадобиться специальный класс операторов. У LIKE '%SQL%' нет фиксированного начала, поэтому такой поиск не получает то же преимущество обычного B-tree. Это ограничение описано в документации типов индексов.
По таблице из девяти товаров нельзя оценить ускорение: последовательное чтение здесь дёшево. Если поиск стал медленным на реальных данных, проверь план через EXPLAIN ANALYZE, затем выбирай индекс под фактическое условие. Варианты для текстового поиска разобраны в руководстве по индексам PostgreSQL.
Для самостоятельной проверки найди товары, названия которых содержат буквальное подчёркивание или знак процента. На этой таблице должны остаться только id 4 и 5; usb-c cable в ответ попадать не должен.
Частые вопросы
Чем LIKE отличается от =
= сравнивает строки целиком и не знает масок. LIKE без % и _ делает то же самое, только читается хуже: для точного совпадения пиши name = 'SQL'. Маски нужны, когда известна только часть значения.
Как искать по нескольким шаблонам одним условием
В PostgreSQL шаблоны можно передать массивом:
SELECT id, name
FROM products
WHERE name ILIKE ANY (ARRAY['sql%', '%cable'])
ORDER BY id;
Ответ — id 1, 2, 5, 6 и 9: названия, которые начинаются с sql в любом регистре или заканчиваются на cable. Переносимая запись — несколько условий через OR.
Почему LIKE ‘%слово%’ медленный и как его ускорить
Поиск по середине строки не может опереться на обычный B-tree: индекс упорядочен по началу значения, а начало неизвестно. В PostgreSQL для таких запросов ставят индекс по триграммам из расширения pg_trgm; варианты индексов для текстового поиска собраны в руководстве по индексам.
Можно ли в LIKE использовать регулярные выражения
Нет: у LIKE только две маски. Для шаблонов сложнее — чередований, повторов, классов символов — в PostgreSQL есть оператор ~ и SIMILAR TO, в MySQL — REGEXP. Они медленнее и не используют обычный индекс, поэтому для простого поиска по началу или части строки LIKE остаётся первым выбором.