Menu

Строковые функции SQLite: SUBSTR, REPLACE, INSTR

Разбираем строковые функции SQLite на практике: конкатенация через ||, SUBSTR, INSTR, REPLACE, TRIM и приёмы для очистки и преобразования текста прямо в запросах.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Строки — это там, где живут реальные запросы

С числами всё просто. А вот строки — это где запросы превращаются в кашу: имена с лишними пробелами, email в разном регистре, ID, склеенные через дефисы, поля со свободным текстом, которые почти-но-не-совсем совпадают. В SQLite есть небольшой, но хорошо продуманный набор строковых функций, который покрывает большую часть таких задач без участия прикладного кода.

На этой странице разберём те, к которым тянется рука первым делом: конкатенация, вырезание подстрок, поиск, замена, обрезка пробелов и форматирование.

Конкатенация строк в SQLite — это ||, а не CONCAT

В SQLite нет функции CONCAT. Строки склеиваются оператором ||:

Числа и значения других типов сами приводятся к тексту. Но есть нюанс: если хотя бы один операнд — NULL, всё выражение тоже превращается в NULL. Это стандартное поведение SQL, но многих оно застаёт врасплох:

Оборачивайте nullable-столбцы в COALESCE(col, '') или COALESCE(col, 'default'), если не хотите, чтобы одно пропущенное значение обнулило всю строку.

LENGTH, UPPER, LOWER

Эта тройка пригодится вам буквально каждый день:

LENGTH возвращает количество символов в тексте, а не байт. Если вам нужны именно байты (редкий случай, но полезный для анализа объёма хранения), используйте OCTET_LENGTH. Функции UPPER и LOWER по умолчанию преобразуют только ASCII-буквы — символы с диакритикой остаются без изменений, пока вы не подключите расширение ICU.

SUBSTR: вырезаем подстроку

Функция SUBSTR(text, start, length) извлекает фрагмент строки. Индексация в SQLite начинается с единицы — 1 означает первый символ, а не 0:

Несколько моментов, которые стоит запомнить:

  • Третий аргумент необязателен. Если его не указать, вернётся всё от позиции start до конца строки.
  • Отрицательный start отсчитывается от конца строки.
  • Если start оказался за пределами строки, вы получите пустую строку, а не ошибку.

В качестве синонима принимается SUBSTRING — пригодится, если мышечная память тянет вас к другой СУБД.

INSTR: поиск подстроки в SQLite

INSTR(haystack, needle) возвращает позицию первого вхождения needle в haystack (нумерация с единицы) или 0, если подстрока не найдена:

Это классическая идиома SQLite для «всего, что идёт до @»: находим разделитель через INSTR, а затем вырезаем нужный кусок с помощью SUBSTR. Такую связку вы будете писать постоянно. Учтите один момент: если совпадений нет, INSTR возвращает 0, и перед вырезанием это стоит проверить — передача 0 в SUBSTR молча выдаёт странный результат.

REPLACE: замена одной подстроки на другую

Функция REPLACE(text, old, new) заменяет каждое вхождение old на new:

Учтите: функция чувствительна к регистру и регулярные выражения не понимает — только точное вхождение подстроки. Для более сложных преобразований можно сцепить несколько REPLACE подряд, но если вложенность переваливает за два-три уровня — пора выносить логику в приложение.

TRIM, LTRIM, RTRIM

Данные, которые ввёл пользователь, частенько приходят с пробелами по краям. TRIM их подчищает:

По умолчанию они убирают пробелы. Если нужно вырезать другие символы, передайте их вторым аргументом — причём каждый символ из этого аргумента воспринимается как элемент «множества для удаления», а не как цельная подстрока. Например, TRIM('xxxhelloxx', 'x') вернёт 'hello'.

printf: форматирование чисел и строк

Когда нужна красиво оформленная строка — фиксированное число знаков после запятой, выравнивание чисел нулями или вывод в шестнадцатеричном виде — на помощь приходит printf (он же format):

Спецификаторы формата здесь — те же, что в C: %d, %s, %f, %x, дополнение нулями или пробелами и так далее. Получается куда чище, чем городить строку через || и кучу CAST-ов.

LIKE vs GLOB: поиск по шаблону

Два оператора — два разных мира.

LIKE работает с классическими SQL-подстановочными символами: % — любая последовательность символов, _ — один символ. Для ASCII регистр не учитывается:

GLOB работает с шаблонами в стиле Unix shell: * — любая последовательность символов, ? — ровно один символ, [abc] — класс символов. При этом регистр учитывается:

Правило выбора простое: LIKE — для «человеческих» запросов в духе «начинается с», «содержит», «заканчивается на». GLOB — когда важен регистр или нужны классы символов. Оба умеют пользоваться индексом, но только если шаблон привязан к началу строки ('foo%', а не '%foo'): ведущий wildcard заставляет SQLite пройтись по всей таблице.

Как разбить строку в SQLite: функции SPLIT здесь нет

В SQLite нет встроенной функции SPLIT_STRING. На практике обходятся двумя способами:

Если нужно разбить строку по разделителю на несколько строк результата, самый чистый вариант — это json_each поверх JSON-массива или рекурсивный CTE. К обоим подходам мы ещё вернёмся в следующих главах, а пока просто держите в голове: в SQLite «дай мне каждое слово» одной строчкой не пишется.

Боевой пример: чистим имена пользователей

Соберём всё вместе. Допустим, есть таблица users с неаккуратными отображаемыми именами: лишние пробелы, разнобой в регистре, плюс опциональные приставки вроде "Dr. " или "Mr. ", от которых хочется избавиться:

Выражение читается изнутри наружу: сначала срезаем пробелы по краям, переводим в нижний регистр, убираем обращения, а затем снова применяем TRIM — на случай, если после удаления обращения остался ведущий пробел. Каждый шаг — это одна функция, а сложность возникает только из-за их вложенности. Если стопка разрослась до четырёх и больше уровней — это уже сигнал: либо завести вычисляемую колонку (см. главу «Продвинутые возможности»), либо очищать данные ещё на этапе импорта.

Что стоит запомнить

  • || склеивает строки; NULL отравляет результат, поэтому подстраховывайтесь через COALESCE.
  • Связка SUBSTR и INSTR закрывает большинство задач в духе «найди и отрежь».
  • REPLACE заменяет все вхождения указанной подстроки.
  • TRIM и его собратья умеют работать не только с пробелами — им можно передать свой набор символов.
  • printf — правильный инструмент, когда нужен форматированный вывод.
  • LIKE — это SQL-шаблоны без учёта регистра, GLOB — шаблоны в стиле шелла с учётом регистра.

Дальше: числовые функции

Со строками разобрались — логично перейти к числам: округление, модуль, особенности деления и математические функции, которые появились в SQLite в последних версиях. Об этом — на следующей странице.

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

Как склеить строки в SQLite?

Через оператор ||, а не CONCAT — функции CONCAT в SQLite попросту нет. Например, 'Привет, ' || name соединит две строки в одну. Важный момент: если хотя бы один из операндов равен NULL, результат тоже будет NULL. Так что если столбец может быть пустым, оборачивайте его в COALESCE.

Как взять подстроку в SQLite?

Используйте SUBSTR(text, start, length) (синоним — SUBSTRING). Нумерация начинается с 1, так что SUBSTR('hello', 1, 3) вернёт 'hel'. Если передать отрицательный start, отсчёт пойдёт с конца строки. Аргумент length необязательный — без него вернётся всё до конца строки.

Есть ли в SQLite функция SPLIT_STRING?

Нет, встроенной функции для разбиения строки в SQLite не предусмотрено. В большинстве случаев нужный кусок можно вытащить связкой INSTR + SUBSTR, либо использовать рекурсивный CTE для разделения по разделителю. Если такая задача встречается часто, удобнее всего хранить данные как JSON-массив и проходить по ним через json_each — это чище, чем городить свой сплиттер.

Чем отличаются LIKE и GLOB в SQLite?

LIKE по умолчанию не учитывает регистр для ASCII-символов и работает с шаблонами % и _. GLOB, наоборот, чувствителен к регистру и использует Unix-подобные шаблоны (*, ?, [abc]). Берите GLOB, когда важен регистр или нужны классы символов; LIKE подойдёт для привычного SQL-стиля поиска по шаблону.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ