Как разбить строку в SQL
Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.
Зачем это нужно аналитику
Разбить строку — базовая задача при работе с грязными данными. В колонке full_name лежит 'Иван Иванов' — нужно разделить на first и last. В email-е 'alice@example.com' хотите извлечь домен. В URL 'https://site.ru?utm_source=google&utm_medium=cpc' — достать UTM.
На собесе часто спрашивают: «разбей полное имя на first / last в SQL». Junior ответит «не знаю». Middle — SPLIT_PART в Postgres или SUBSTRING_INDEX в MySQL. Senior обсудит нюансы (что если больше двух слов, что если есть null).
В статье — все способы разбиения:
- SPLIT_PART в Postgres
- SUBSTRING_INDEX в MySQL
- STRING_TO_ARRAY + unnest (Postgres)
- splitByChar в ClickHouse
- SUBSTRING для фиксированных позиций
1. SPLIT_PART в Postgres
Взять N-ю часть по разделителю:
SELECT SPLIT_PART('Иван Иванов Иванович', ' ', 1); -- 'Иван'
SELECT SPLIT_PART('Иван Иванов Иванович', ' ', 2); -- 'Иванов'
SELECT SPLIT_PART('Иван Иванов Иванович', ' ', 3); -- 'Иванович'
SELECT SPLIT_PART('alice@example.com', '@', 2); -- 'example.com'Если части N не существует — возвращает пустую строку.
2. SUBSTRING_INDEX в MySQL
-- взять часть до 1-го пробела
SELECT SUBSTRING_INDEX('Иван Иванов Иванович', ' ', 1); -- 'Иван'
-- до 2-го пробела
SELECT SUBSTRING_INDEX('Иван Иванов Иванович', ' ', 2); -- 'Иван Иванов'
-- от конца (отрицательный)
SELECT SUBSTRING_INDEX('Иван Иванов Иванович', ' ', -1); -- 'Иванович'
-- домен email (после @)
SELECT SUBSTRING_INDEX('alice@example.com', '@', -1); -- 'example.com'3. STRING_TO_ARRAY в Postgres
Превратить строку в массив:
SELECT STRING_TO_ARRAY('Иван Иванов Иванович', ' ');
-- {Иван, Иванов, Иванович}
-- по индексу
SELECT (STRING_TO_ARRAY('a,b,c,d', ','))[2]; -- 'b'
-- развернуть в rows
SELECT unnest(STRING_TO_ARRAY('a,b,c', ','));
-- a
-- b
-- c4. REGEXP_SPLIT_TO_ARRAY (Postgres)
По regex:
-- по любому пробельному (пробел, таб, перевод строки)
SELECT REGEXP_SPLIT_TO_ARRAY('Иван Иванов Иванович', '\s+');
-- {Иван, Иванов, Иванович}5. splitByChar в ClickHouse
SELECT splitByChar(' ', 'Иван Иванов Иванович');
-- ['Иван', 'Иванов', 'Иванович']
-- по индексу
SELECT arrayElement(splitByChar(',', 'a,b,c'), 2); -- 'b'6. Практика: разбить full_name
-- Postgres
SELECT
full_name,
SPLIT_PART(full_name, ' ', 1) AS first_name,
SPLIT_PART(full_name, ' ', 2) AS last_name,
SPLIT_PART(full_name, ' ', 3) AS patronymic
FROM users;7. Домен email
-- Postgres
SELECT email, SPLIT_PART(email, '@', 2) AS domain FROM users;
-- MySQL
SELECT email, SUBSTRING_INDEX(email, '@', -1) AS domain FROM users;8. UTM из URL
-- Postgres (regex)
SELECT
url,
REGEXP_MATCHES(url, 'utm_source=([^&]+)') AS utm_source,
REGEXP_MATCHES(url, 'utm_medium=([^&]+)') AS utm_medium
FROM visits;9. Разбить CSV-колонку на строки
Если в колонке tags = 'vip,new,premium' — развернуть:
-- Postgres
SELECT user_id, unnest(STRING_TO_ARRAY(tags, ',')) AS tag
FROM users;Это как реляционная нормализация на лету.
10. Обработка null
-- если null → пустая строка, чтобы SPLIT_PART не упал
SELECT SPLIT_PART(COALESCE(email, ''), '@', 2);Частые ошибки
1. Индекс с 1 или 0
В SQL обычно с 1. В Python — с 0. Не путать.
2. Разделитель — regex vs literal
В REGEXP_SPLIT_TO_ARRAY — regex. В STRING_TO_ARRAY — литерал.
3. Пустые части
'a,,b' разбитое по , → ['a', '', 'b']. 3 части, средняя пустая.
4. Performance на миллиардах
Разбиение в runtime медленное. Лучше нормализовать данные в ETL.
Связанные темы
FAQ
SPLIT_PART в MySQL?
Нет. Используйте SUBSTRING_INDEX.
Как разбить по нескольким разделителям?
Regex: REGEXP_SPLIT_TO_ARRAY('a,b;c', '[,;]').
Очень длинные CSV в колонке?
Рассмотрите нормализацию: отдельная таблица user_tags.
JSON как разбить?
Не через string split. Используйте JSON-функции.
Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.