Строковые функции SQL: шпаргалка для собеседования

Зачем аналитику строковые функции

Чистка данных, парсинг URL, извлечение доменов из email, normalized join по имени — строковые функции нужны в каждом проекте. На собесе их спрашивают в блоке «очистка данных».

Базовые функции

Функция Что делает Пример
LOWER(s) К нижнему регистру 'HELLO' → 'hello'
UPPER(s) К верхнему регистру 'hello' → 'HELLO'
LENGTH(s) Длина строки 'abc' → 3
TRIM(s) Убрать пробелы с краёв ' abc ' → 'abc'
LTRIM/RTRIM(s) Слева/справа
REVERSE(s) Перевернуть 'abc' → 'cba'

Извлечение подстроки

SUBSTRING / SUBSTR

-- PostgreSQL, ClickHouse
SELECT SUBSTRING('2026-04-15', 1, 4) AS year;  -- '2026'
SELECT SUBSTRING('2026-04-15', 6, 2) AS month; -- '04'

-- SUBSTR (алиас)
SELECT SUBSTR('hello world', 7) AS s;  -- 'world'

Индексация с 1, не с 0 — частая ловушка у тех, кто привык к Python.

LEFT / RIGHT

SELECT LEFT('example.com', 7) AS l;   -- 'example'
SELECT RIGHT('example.com', 3) AS r;  -- 'com'

SPLIT_PART (PostgreSQL)

Разделить строку по разделителю и взять N-й элемент:

SELECT SPLIT_PART('user@example.com', '@', 1) AS username;  -- 'user'
SELECT SPLIT_PART('user@example.com', '@', 2) AS domain;    -- 'example.com'

В MySQL: SUBSTRING_INDEX. В ClickHouse: splitByChar + array index.

Замена и конкатенация

REPLACE

SELECT REPLACE('hello world', 'world', 'SQL') AS s;  -- 'hello SQL'
-- Удалить все пробелы
SELECT REPLACE('   a b c   ', ' ', '') AS s;  -- 'abc'

CONCAT / ||

-- PostgreSQL: || игнорирует NULL? НЕТ, || с NULL → NULL
SELECT 'Hello, ' || name AS greeting FROM users;

-- CONCAT игнорирует NULL
SELECT CONCAT('Hello, ', name) FROM users;

-- CONCAT_WS — с разделителем
SELECT CONCAT_WS(' ', first_name, middle_name, last_name) FROM users;

CONCAT_WS особенно полезна

Если middle_name = NULL, || выдаст NULL, CONCAT_WS пропустит NULL. Для склейки full_name это спасает.

Тренироваться на таких вопросах можно в Telegram-боте Карьерник — там 1500+ задач с реальных собесов с разборами.

Поиск и сопоставление

LIKE

SELECT * FROM users WHERE email LIKE '%@gmail.com';     -- заканчивается
SELECT * FROM users WHERE name LIKE 'А%';               -- начинается с А
SELECT * FROM users WHERE phone LIKE '+7___999%';       -- _ = любой один символ

Важно: LIKE чувствителен к регистру в большинстве СУБД. Для case-insensitive — ILIKE в PostgreSQL.

POSITION / INSTR

Позиция подстроки в строке:

SELECT POSITION('@' IN 'user@example.com') AS pos;  -- 5
SELECT STRPOS('user@example.com', '@');              -- 5 (PostgreSQL)

Возвращает 0, если не найдено.

Регулярные выражения

Сильный инструмент, спрашивают на middle-позициях.

PostgreSQL

-- Проверка
SELECT 'abc123' ~ '[0-9]+' AS has_digits;   -- TRUE

-- Извлечь первое совпадение
SELECT REGEXP_MATCHES('Phone: +79991234567', '\+?\d+');

-- Заменить
SELECT REGEXP_REPLACE('Hello 123 world', '[0-9]+', 'X');  -- 'Hello X world'

-- Разбить
SELECT REGEXP_SPLIT_TO_ARRAY('a,b;c|d', '[,;|]');

Проверка email

SELECT email FROM users
WHERE email ~* '^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$';

Извлечение домена

SELECT SUBSTRING(email FROM '@(.+)$') AS domain FROM users;

Преобразование типов

-- Строка → число
SELECT '123'::INTEGER;
SELECT CAST('3.14' AS FLOAT);

-- Число → строка
SELECT (42)::TEXT;
SELECT CAST(42 AS VARCHAR);

-- Безопасно: в PostgreSQL будет ошибка если '123abc' преобразовывать в INT
-- В ClickHouse есть toInt32OrNull

Чистка данных — типовые операции

Нормализация пользовательского ввода

SELECT LOWER(TRIM(email)) AS clean_email FROM users;

Удаление тегов HTML

SELECT REGEXP_REPLACE(description, '<[^>]+>', '', 'g') AS plain FROM products;

Удаление всего, кроме цифр

SELECT REGEXP_REPLACE(phone, '[^0-9]', '', 'g') AS digits_only FROM users;

Маска телефона

SELECT CONCAT(
    '+7 (', SUBSTRING(phone FROM 2 FOR 3), ') ',
    SUBSTRING(phone FROM 5 FOR 3), '-',
    SUBSTRING(phone FROM 8 FOR 2), '-',
    SUBSTRING(phone FROM 10 FOR 2)
) AS formatted
FROM users;

К слову, набить руку на таких кейсах удобно через тренажёр в Telegram — разбирайте по 10 вопросов в день, через 2 недели тема становится рефлексом.

10 задач с собеседований

1. Извлечь домен из email

SELECT SPLIT_PART(email, '@', 2) AS domain FROM users;

2. Топ-10 самых популярных доменов

SELECT SPLIT_PART(email, '@', 2) AS domain, COUNT(*)
FROM users GROUP BY 1 ORDER BY 2 DESC LIMIT 10;

3. Найти пользователей с кириллицей в имени

SELECT * FROM users WHERE name ~ '[а-яА-Я]';

4. Маскировать email (показать только первую букву)

SELECT LEFT(email, 1) || '***@' || SPLIT_PART(email, '@', 2) AS masked
FROM users;

5. Убрать все пробелы из номера

SELECT REPLACE(phone, ' ', '') FROM users;

6. Нормализовать имена (первая заглавная)

SELECT INITCAP(LOWER(name)) FROM users;  -- 'JOHN doe''John Doe'

7. Число слов в описании

SELECT LENGTH(description) - LENGTH(REPLACE(description, ' ', '')) + 1 AS word_count
FROM products;

8. Фильтр по префиксу телефона

SELECT * FROM users WHERE phone LIKE '+7%';

9. Извлечь UTM-source из URL

SELECT SUBSTRING(url FROM 'utm_source=([^&]+)') AS source FROM visits;

10. Найти дубликаты по нормализованному имени

SELECT LOWER(TRIM(name)), COUNT(*)
FROM users
GROUP BY LOWER(TRIM(name))
HAVING COUNT(*) > 1;

Как тренироваться

Строковые функции — про запомнить 10-15 базовых. SUBSTRING, REPLACE, SPLIT_PART, POSITION, LIKE, REGEXP — ими покрываются 95% задач. Остальное гуглится.

Тренажёр Карьерник содержит блок на строковые функции: парсинг, регулярки, нормализация, очистка. Учатся за пару дней до автоматизма.

Совет: на собесе, когда показывают «очистите эту таблицу», начинайте с LOWER+TRIM — это закрывает 50% грязи. Потом переходите к REGEXP и SPLIT по ситуации.

Читайте также

FAQ

В чём разница между || и CONCAT?

|| при встрече с NULL даёт NULL (из-за чего теряется вся строка). CONCAT игнорирует NULL — заменяет на пустую строку. Для склейки full_name где любое поле может быть NULL — всегда CONCAT или CONCAT_WS.

LIKE или REGEXP?

LIKE для простых шаблонов (начинается с, заканчивается на, содержит). REGEXP — для сложных (email, номер телефона, форматы с цифрами). LIKE быстрее из-за простоты.

Как сделать case-insensitive сравнение?

Либо LOWER(col) = LOWER('value'), либо ILIKE (PostgreSQL). Первый вариант работает во всех СУБД. ILIKE использует тот же индекс, что обычный LIKE.

Есть ли STRING_AGG для склейки группы?

Да, STRING_AGG(col, ', ') в PostgreSQL, GROUP_CONCAT в MySQL. См. шпаргалку по агрегатам.