Оператор LIKE в SQL: как выбрать строки по шаблону и по слову в поле

Чтобы выбрать строки, где поле содержит слово, пишут WHERE name LIKE '%слово%'.

На одной таблице разбираем, чем PostgreSQL, MySQL и SQLite отличаются по регистру, как найти сам знак процента, искать сразу по нескольким словам и почему шаблон с процентом в начале не использует обычный индекс.

Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 3177 статей автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 3831 экспертное мнение Подписаться на Телеграм-канал
Обложка: Оператор LIKE в SQL: как выбрать строки по шаблону и по слову в поле

Чтобы выбрать строки, в которых поле содержит слово, поставьте в WHERE оператор LIKE и обложите слово знаками процента: SELECT * FROM products WHERE name LIKE '%ноутбук%';. Знак % заменяет любое число символов, в том числе ноль, а _ заменяет ровно один символ.

Главный подвох в регистре. PostgreSQL отличает «Ноутбук» от «ноутбук», MySQL по умолчанию нет, а SQLite игнорирует регистр только у латинских букв. Ниже разберём все случаи на одной таблице, а заодно NOT LIKE, поиск по нескольким словам, экранирование и индексы. Если запросы SELECT вам пока в новинку, начните с разбора команды SELECT в MySQL или с общего рассказа о том, как устроен язык SQL.

CheckroiCheckroiПодборка курсов по SQL422 курса • 40 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Синтаксис LIKE и два подстановочных знака

Рой пишет SQL-запрос с LIKE за ноутбуком

LIKE сравнивает строку с шаблоном и возвращает истину, если строка шаблону подходит. Пишется он внутри WHERE, как и любое другое условие:

SELECT столбцы
FROM таблица
WHERE столбец LIKE 'шаблон';

В шаблоне работают два специальных символа. Всё остальное сравнивается буква в букву.

Символ Что заменяет Шаблон Подойдёт
% любое число символов, включая ноль 'Мышь%' «Мышь», «Мышь Logitech M185»
_ ровно один любой символ 'CB-0_' «CB-01», «CB-02», но не «CB-010»

Шаблон всегда описывает строку целиком. В документации PostgreSQL сказано: «LIKE pattern matching always covers the entire string», поэтому для поиска слова в середине процент нужен с обеих сторон. Без единого % и _ LIKE работает как обычное равенство.

Все примеры ниже идут по такой учебной таблице товаров:

CREATE TABLE products (id INT PRIMARY KEY, name VARCHAR(100), sku VARCHAR(20));
INSERT INTO products VALUES
 (1, 'Ноутбук Lenovo IdeaPad 5', 'NB-001'),
 (2, 'ноутбук ASUS VivoBook 15', 'NB-002'),
 (3, 'Чехол для ноутбука 15,6 дюйма', 'AC-101'),
 (4, 'Мышь Logitech M185', 'MS-185'),
 (5, 'Клавиатура Logitech K380', 'KB-380'),
 (6, 'Монитор Samsung 27, скидка 10%', 'MN-270'),
 (7, 'Кабель USB_C 1 м', 'CB-01'),
 (8, 'Кабель USB-C 2 м', 'CB-02'),
 (9, NULL, 'XX-000');

Запросы мы выполнили в PostgreSQL 17, MySQL 8.0 и SQLite 3.51. Вывод ниже взят из PostgreSQL, а там, где другие СУБД отвечают иначе, это показано отдельно.

Как выбрать строки по шаблону: начало, середина и конец поля

Положение знака процента определяет, где в строке должен стоять искомый кусок. Это самые частые запросы с LIKE, и почти все остальные строятся из них.

Поле начинается с текста

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

 id |           name
----+--------------------------
  1 | Ноутбук Lenovo IdeaPad 5

Вторая строка, «ноутбук ASUS…», сюда не попала, потому что PostgreSQL различает заглавную и строчную букву. MySQL на той же таблице вернёт обе строки. Почему так, разберём в разделе про регистр.

Поле содержит слово в любом месте

Так в SQL выглядит проверка «поле содержит текст», которую в других языках называют contains: процент ставится и до, и после слова.

SELECT id, name FROM products WHERE name LIKE '%ноутбук%';

 id |             name
----+-------------------------------
  2 | ноутбук ASUS VivoBook 15
  3 | Чехол для ноутбука 15,6 дюйма

Обратите внимание на третью строку. Шаблон '%ноутбук%' находит и «ноутбука», и «ноутбуком»: LIKE ищет кусок строки, границы слов ему безразличны. Если нужно отдельное слово, выручает полнотекстовый поиск, о нём ниже.

Поле заканчивается на текст

SELECT id, name FROM products WHERE name LIKE '%15';

 id |           name
----+--------------------------
  2 | ноутбук ASUS VivoBook 15

Фиксированная длина через подчёркивание

Подчёркивание удобно для артикулов и кодов, где важна позиция символа. Шаблон '__-1%' читается так: два любых символа, дефис, единица, дальше что угодно.

SELECT id, sku FROM products WHERE sku LIKE '__-1%';

 id |  sku
----+--------
  3 | AC-101
  4 | MS-185

Шаблоны свободно сочетаются с другими частями запроса. Найденное можно отсортировать через ORDER BY или пересчитать функцией COUNT.

Канал основателя Checkroi Вани Буявца3 800 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

NOT LIKE и строки с NULL

NOT LIKE переворачивает условие и оставляет строки, которые шаблону не подходят. Посчитаем товары без слова Logitech:

SELECT COUNT(*) FROM products WHERE name NOT LIKE '%Logitech%';

 count
-------
     6

В таблице девять строк, Logitech встречается в двух, а в ответе шесть, не семь. Пропала строка с name = NULL.

Решение: помнить, что сравнение с NULL даёт не «ложь», а неизвестность. NULL LIKE '%' возвращает NULL, и такую строку не выберет ни LIKE, ни NOT LIKE. Даже WHERE name LIKE '%' вернёт восемь строк, а не девять. Нужны пустые значения в выборке, добавьте их явно: WHERE name NOT LIKE '%Logitech%' OR name IS NULL. Подробнее эта логика разобрана в статье про NULL в SQL.

Регистр букв: где «Ноутбук» и «ноутбук» считаются разными

Один и тот же запрос LIKE '%ноутбук%' на одной таблице вернул в трёх СУБД разное число строк. Причина в том, как каждая из них сравнивает буквы.

СУБД Регистр в LIKE Строк по ‘%ноутбук%’ Как искать без учёта регистра
PostgreSQL различает 2 ILIKE или LOWER(name) LIKE …
MySQL 8.0 не различает при сопоставлении по умолчанию 3 ничего не нужно; для точного регистра COLLATE utf8mb4_0900_as_cs
SQLite игнорирует только у латиницы 2 для кириллицы хранить копию в нижнем регистре

PostgreSQL: ILIKE

В PostgreSQL есть отдельный оператор ILIKE. В той же документации прямо сказано, что его нет в стандарте SQL: «This is not in the SQL standard but is a PostgreSQL extension». В MySQL и SQLite такой запрос упадёт с ошибкой синтаксиса.

SELECT id, name FROM products WHERE name ILIKE '%ноутбук%';

 id |             name
----+-------------------------------
  1 | Ноутбук Lenovo IdeaPad 5
  2 | ноутбук ASUS VivoBook 15
  3 | Чехол для ноутбука 15,6 дюйма

Переносимый вариант WHERE LOWER(name) LIKE '%ноутбук%' в PostgreSQL дал те же три строки.

MySQL: регистр решает сопоставление

В MySQL 8.0 таблицы по умолчанию создаются с сопоставлением utf8mb4_0900_ai_ci, где ci означает case-insensitive. Справка MySQL называет это прямо: «nonbinary string comparisons are case-insensitive by default». Поэтому 'Ноутбук%' находит и строку со строчной буквы.

Вторая часть названия, ai, означает accent-insensitive. На практике это значит, что 'ёж' LIKE 'еж' в MySQL возвращает 1, а в PostgreSQL false. Для поиска по русским текстам это скорее плюс, но о нём стоит знать. Точное совпадение с регистром даёт другое сопоставление: WHERE name COLLATE utf8mb4_0900_as_cs LIKE '%ноутбук%' вернул две строки, как PostgreSQL. Старый приём LIKE BINARY тоже работает, но MySQL 8.0 отвечает на него предупреждением 1287: «’BINARY expr’ is deprecated».

SQLite: ловушка с кириллицей

В справке SQLite написано: «SQLite only understands upper/lower case for ASCII characters by default». На деле это выглядит так: LIKE '%logitech%' находит «Logitech», а LIKE 'ноутбук%' находит только строку со строчной буквы. И LOWER() тут не спасает: встроенная функция тоже понимает только латиницу, и запрос с ней вернул две строки вместо трёх.

Решение: хранить рядом колонку с текстом, приведённым к нижнему регистру ещё в приложении, и искать по ней. Второй путь подсказывает сама справка: в расширении ICU своя версия LIKE, которая сравнивает без учёта регистра все символы Юникода.

Как найти сам знак процента или подчёркивание

В таблице есть «Кабель USB_C» и «Кабель USB-C». Шаблон '%USB_C%' находит оба, потому что подчёркивание в нём означает «любой символ», а не сам знак.

Чтобы % или _ искался буквально, перед ним ставят экранирующий символ. Надёжнее всего назначить его явно через ESCAPE. Такой запрос одинаково сработал в PostgreSQL, MySQL и SQLite:

SELECT id, name FROM products WHERE name LIKE '%10!%%' ESCAPE '!';

 id |              name
----+--------------------------------
  6 | Монитор Samsung 27, скидка 10%

Короткая запись с обратным слешем, LIKE '%USB\_C%', работает не везде. В PostgreSQL и MySQL слеш служит экранирующим символом по умолчанию, оба вернули только строку 7. В SQLite тот же запрос не нашёл ничего, пока мы не дописали ESCAPE '\'. В SQL Server значения по умолчанию у экранирующего символа тоже нет, справка Microsoft приводит ровно тот же приём с восклицательным знаком.

-- SQLite: без ESCAPE слеш считается обычным символом
SELECT id, name FROM products WHERE name LIKE '%USB\_C%' ESCAPE '\';

id  name
--  ----------------
7   Кабель USB_C 1 м

Поиск по нескольким словам сразу

Картотека, где лупа выделяет карточки с нужным словом

Отдельного синтаксиса для списка шаблонов в стандартном SQL нет, поэтому условия соединяют через AND и OR. Что выбрать, зависит от задачи.

  • Все слова есть в поле: name LIKE '%Logitech%' AND name LIKE '%M185%'. Порядок слов не важен.
  • Слова идут в заданном порядке: name LIKE '%Logitech%M185%'. Одно условие вместо двух, но «M185 Logitech» уже не найдётся.
  • Хотя бы одно слово: name LIKE '%Lenovo%' OR name LIKE '%ASUS%'.
SELECT id, name FROM products
WHERE name LIKE '%Lenovo%' OR name LIKE '%ASUS%';

 id |           name
----+--------------------------
  1 | Ноутбук Lenovo IdeaPad 5
  2 | ноутбук ASUS VivoBook 15

Когда вариантов больше трёх, цепочка OR разрастается. В PostgreSQL её сворачивают в массив: name LIKE ANY (ARRAY['%Lenovo%', '%ASUS%']) для «любого слова» и LIKE ALL (…) для «всех слов». В MySQL то же делает регулярное выражение name REGEXP 'Lenovo|ASUS', в PostgreSQL его аналог name ~ 'Lenovo|ASUS'. Все три запроса вернули те же две строки.

А вот name IN ('%Lenovo%', '%ASUS%') не вернёт ничего. IN сравнивает на точное равенство, и проценты в нём остаются просто символами. Если OR внутри WHERE смешивается с другими условиями, берите его в скобки, иначе AND сработает раньше. А когда строки нужно не отфильтровать, а пометить, LIKE ставят внутрь оператора CASE: CASE WHEN name LIKE '%Logitech%' THEN 'периферия' ELSE 'другое' END.

Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 800 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

Индексы: почему запрос с процентом в начале тормозит

На восьми строках разницы не видно. Мы проверили на таблице из 200 тысяч адресов почты с обычным индексом по колонке email в PostgreSQL 17. План запроса показывает команда EXPLAIN, её можно запустить в psql или в любом клиенте, например в DBeaver (как подключить DBeaver к PostgreSQL).

EXPLAIN SELECT * FROM clients WHERE email LIKE 'client777%';

 Seq Scan on clients  (cost=0.00..3908.00 rows=20 width=24)
   Filter: (email ~~ 'client777%'::text)

Индекс есть, а база всё равно перебирает всю таблицу. Причина в том, что база создана с русской локалью, а обычный индекс сравнивает строки по её правилам. По документации PostgreSQL, для такого случая подходит класс операторов text_pattern_ops: он сравнивает строки посимвольно, поэтому годится для LIKE, когда база работает не с локалью C.

CREATE INDEX clients_email_pattern_idx ON clients (email text_pattern_ops);
EXPLAIN SELECT * FROM clients WHERE email LIKE 'client777%';

 Index Scan using clients_email_pattern_idx on clients  (cost=0.42..8.44 rows=20 width=24)
   Index Cond: ((email ~>=~ 'client777'::text) AND (email ~<~ 'client778'::text))

Оценка стоимости упала с 3908 до 8,44. Но с шаблоном '%777@%' этот индекс бесполезен: B-дерево умеет искать только от начала строки, и план снова превращается в Seq Scan.

Решение для процента в начале: триграммный индекс из расширения pg_trgm. В его документации сказано, что поиск по такому индексу работает и для LIKE, причём шаблон «need not be left-anchored».

CREATE EXTENSION pg_trgm;
CREATE INDEX clients_email_trgm_idx ON clients USING gin (email gin_trgm_ops);
EXPLAIN SELECT * FROM clients WHERE email LIKE '%777@%';

 Bitmap Heap Scan on clients  (cost=21.59..94.69 rows=20 width=24)
   Recheck Cond: (email ~~ '%777@%'::text)
   ->  Bitmap Index Scan on clients_email_trgm_idx  (cost=0.00..21.59 rows=20 width=0)

В MySQL на той же таблице картина похожая: шаблон 'client777%' идёт диапазоном по индексу, а '%777@%' заставляет читать индекс целиком. Умение прочитать такой план отличает того, кто пишет запросы, от того, кто их ускоряет. Обычно это уже работа SQL-аналитика или разработчика баз данных.

LIKE или CONTAINS: когда нужен полнотекстовый поиск

По аналогии с другими языками хочется написать CONTAINS, но такой оператор есть не во всех СУБД. В SQL Server это предикат полнотекстового поиска: по справке Microsoft, он ищет «по столбцам полнотекстового индекса». Значит, сначала на колонку нужно построить такой индекс, а для простого поиска по подстроке и в SQL Server берут LIKE.

Что нужно Чем искать
подстрока в любом месте, короткие поля LIKE '%текст%'
сложный шаблон, варианты через «или» REGEXP в MySQL, ~ или SIMILAR TO в PostgreSQL
отдельные слова и формы слова в длинных текстах полнотекстовый индекс: CONTAINS в SQL Server, MATCH … AGAINST в MySQL

В MySQL полнотекстовый поиск выглядит так. Звёздочка в конце слова нашла и «ноутбук», и «ноутбука»:

ALTER TABLE products ADD FULLTEXT INDEX ft_name (name);
SELECT id, name FROM products
WHERE MATCH(name) AGAINST('ноутбук*' IN BOOLEAN MODE);

+----+-------------------------------+
| id | name                          |
+----+-------------------------------+
|  1 | Ноутбук Lenovo IdeaPad 5      |
|  2 | ноутбук ASUS VivoBook 15      |
|  3 | Чехол для ноутбука 15,6 дюйма |
+----+-------------------------------+

В SQL Server LIKE понимает ещё и квадратные скобки: LIKE '[C-P]arsen' ищет один символ из диапазона, а [^…] исключает его. Это расширение Transact-SQL. В PostgreSQL, MySQL и SQLite внутри LIKE скобки остаются обычными символами: 'Carsen' LIKE '[C-P]arsen' во всех трёх вернул ложь.

Частые ошибки и что с ними делать

Рой радуется, что запрос нашёл все нужные строки
  1. Запрос ничего не находит, хотя данные есть. Обычно в шаблоне забыли процент: LIKE 'ноутбук' ищет поле, равное слову целиком. Решение: '%ноутбук%'.
  2. В PostgreSQL ошибка «оператор не существует: integer ~~ unknown». LIKE применили к числовой колонке: WHERE id LIKE '1%'. MySQL и SQLite молча приводят число к строке, PostgreSQL нет. Решение: явное приведение id::text LIKE '1%'.
  3. Нашлось больше строк, чем ожидали. В искомом тексте есть _ или %, и они сработали как шаблон. Решение: экранировать через ESCAPE, как в разделе выше.
  4. Запрос работает в MySQL и ломается при переезде на PostgreSQL. В нём неявно работало регистронезависимое сравнение MySQL. Решение: ILIKE или LOWER() с обеих сторон.
  5. NOT LIKE «теряет» строки. Это строки с NULL в колонке. Решение: дописать OR name IS NULL или заменить пустое значение через функцию COALESCE.

LIKE работает и в соединениях: шаблоном можно отфильтровать строки уже после JOIN нескольких таблиц, правила те же.

Где освоить SQL системно

LIKE закрывает одну задачу: найти строки по куску текста. Аналитику и разработчику каждый день нужны ещё группировки, соединения, оконные функции и чтение планов запросов. Как выглядит путь от первых SELECT до работы, мы расписали в статье о том, как стать SQL-разработчиком, а ниже собрали курсы, где эти темы идут по порядку и с практикой.

КурсШколаСтоимость со скидкойВ рассрочкуДлитель­ностьОбзор курса от Checkroi
Нейросети для рабочих задач
Перейти на сайт курса
SkillboxSkillbox31 290 ₽ - 1 месяцОбзор курса
SQL для анализа данных
Перейти на сайт курса
SkillboxSkillbox50 865 ₽6203 ₽/мес.2 месяцаОбзор курса
SQL-разработчик: тариф PRO
Перейти на сайт курса
Академия ЭдюсонЭдюсон89 900 ₽7491 ₽/мес.2 месяцаОбзор курса
SQL-разработчик: тариф Базовый
Перейти на сайт курса
Академия ЭдюсонЭдюсон79 900 ₽3329 ₽/мес.3 месяцаОбзор курса
Data-Driven подход в разработке продукта: SQL и Yandex DataLens
Перейти на сайт курса
ProductStarProductStar29 990 ₽2999 ₽/мес.1 месяцОбзор курса

Больше программ — в полном каталоге курсов по SQL

Часто задаваемые вопросы

Чем LIKE отличается от знака равенства?

Если в шаблоне нет ни %, ни _, LIKE сравнивает строку целиком и работает как =. С подстановочными знаками он ищет совпадение по шаблону: начало, конец или кусок в середине поля.

Как сделать LIKE без учёта регистра?

В PostgreSQL используйте ILIKE или LOWER(name) LIKE '%слово%'. В MySQL 8.0 при сопоставлении по умолчанию LIKE и так не различает регистр. SQLite игнорирует регистр только у латиницы, для кириллицы надёжнее хранить копию текста в нижнем регистре.

Можно ли использовать LIKE вместе с IN?

Нет. IN ('%Lenovo%', '%ASUS%') ищет точное равенство, и проценты там остаются обычными символами. Соединяйте условия через OR, в PostgreSQL пишите LIKE ANY (ARRAY[…]), в MySQL подойдёт REGEXP 'Lenovo|ASUS'.

Как найти строки, в которых нет нужного слова?

Через NOT LIKE '%слово%'. Учтите, что строки с NULL в колонке такой запрос не вернёт: если они нужны, допишите OR name IS NULL.

Почему запрос с LIKE '%текст%' работает медленно?

Обычный B-tree индекс ищет только от начала строки, поэтому шаблон с процентом в начале заставляет базу перебрать всю таблицу или весь индекс. В PostgreSQL помогает триграммный индекс из расширения pg_trgm, для длинных текстов лучше подходит полнотекстовый поиск.

Как найти в тексте сам знак процента или подчёркивание?

Поставьте перед ним экранирующий символ и объявите его через ESCAPE: LIKE '%10!%%' ESCAPE '!'. Такая запись одинаково работает в PostgreSQL, MySQL и SQLite, а короткая форма с обратным слешем в SQLite без ESCAPE не срабатывает.

Читайте Checkroi первым в Google
Добавьте Checkroi в избранные источники — и наши разборы курсов и обзоры школ будут показываться выше в вашей выдаче Google.
Оставить комментарий
0 комментариев
Форма комментария

Оставьте комментарий

Напишите, что думаете. Нам важно ваше мнение!