LIKE и ILIKE в SQL: поиск по шаблону с примерами

опубликовано
обновлено
читать
≈ 9 мин
автор
среда и версия
PostgreSQL 17.9, локаль en_US.utf8; вся последовательность выполнена в отдельной учебной базе 27 октября 2026; поведение SQLite проверено на 3.50.2, MySQL и SQL Server — по документации
содержание решать задачи SQL для аналитиков

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.

SQL / 01

Знак % допускает и суффикс, и его отсутствие

Результат LIKE SQL% для четырёх значенийШаг 1: берём название товара. Шаг 2: проверяем LIKE 'SQL%'. Шаг 3: SQL guide и SQL дают true, sql workbook даёт false, NULL даёт неизвестный результат NULL. WHERE оставляет только true.01 / название02 / проверка03 / результатSQL guideLIKE 'SQL%'trueSQLLIKE 'SQL%'truesql workbookLIKE 'SQL%'falseNULLLIKE 'SQL%'NULL
LIKE 'SQL%' пропустит строки 1 и 9. Для строки с NULL результат неизвестен, поэтому она в выборку не попадёт.

SQL LIKE: начало, конец и часть строки

Выберем товары, названия которых начинаются с SQL:

SELECT id, name
FROM products
WHERE name LIKE 'SQL%'
ORDER BY id;

Результат:

idname
1SQL guide
9SQL

Товар SQL тоже подходит: % разрешает ноль символов. Без маски шаблон LIKE 'SQL' на нашей таблице совпадёт только с названием SQL; для обычного равенства понятнее написать name = 'SQL'.

Положение % меняет условие. Каждый шаблон из таблицы можно подставить в тот же запрос:

УсловиеЗадачаПодходящие id
name LIKE 'SQL%'Начинается с SQL1, 9
name LIKE '%cotton'Заканчивается на cotton4
name LIKE '%SQL%'Содержит SQL в любой позиции1, 3, 9
name LIKE 'SQL'Целиком совпадает с SQL9

LIKE сопоставляет всю строку. Без % по краям он не ищет фрагмент автоматически. Звёздочка * здесь тоже не заменяет %: это обычный символ, а не маска SQL LIKE.

Символ _ заменяет ровно один символ

Такой запрос найдёт два кабеля:

SELECT id, name
FROM products
WHERE name LIKE 'usb_c cable'
ORDER BY id;
idname
5usb_c cable
6usb-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;
idname
1SQL guide
2sql workbook
9SQL

PostgreSQL handbook не попал в ответ: слово начинается с Postgre, а шаблон требует sql в начале. Для поиска в любой позиции используй ILIKE '%sql%' — на наших данных это строки 1, 2, 3 и 9.

Для нелатинских названий проверяй поведение на локали своей базы. ILIKE не означает поиск похожих слов: он не исправляет опечатки и не делает транслитерацию.

LIKE в MySQL, SQL Server и SQLite

Маски % и _ одинаковы везде, а регистр и дополнительные возможности зависят от СУБД:

СУБДРегистр в LIKEЧего нет и что есть дополнительно
PostgreSQLучитывается; без учёта — ILIKESIMILAR TO и регулярные выражения через оператор ~
MySQLзависит от сопоставления колонки: при сопоставлениях *_ci, которые стоят по умолчанию, регистр не учитываетсяILIKE нет; учесть регистр — LIKE BINARY или сопоставление *_bin
SQL Serverзависит от сопоставления: у большинства по умолчанию _CI, регистр не учитываетсяILIKE нет; в шаблоне есть [абв] и [^абв] — набор или диапазон символов на одной позиции
SQLiteне учитывается только для латиницы ASCII: 'ABC' LIKE 'abc' даёт 1, а 'Ярд' LIKE 'ярд' — 0ILIKE нет; 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 остаётся первым выбором.

Источники