Как обрезать строку в SQL

Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.

Зачем это нужно

Грязные данные — ежедневная реальность аналитика. В колонке email лежит ' ALICE@example.com ' — с пробелами и в верхнем регистре. Сравнение email = 'alice@example.com' не находит, фильтры ломаются, GROUP BY разделяет одного пользователя на двух.

Обрезка строк — базовый навык. На собеседовании часто просят: «в данных email с пробелами, как найти дубликаты». Правильный ответ: LOWER(TRIM(email)). Не знаете — минус балл.

В статье:

  • TRIM / LTRIM / RTRIM — убрать пробелы
  • SUBSTRING — взять часть
  • LEFT / RIGHT — взять с начала / конца
  • LENGTH для проверки
  • REPLACE для замены

1. TRIM — убрать пробелы

SELECT TRIM('  hello  ');      -- 'hello'
SELECT LTRIM('  hello  ');     -- 'hello  '  (только слева)
SELECT RTRIM('  hello  ');     -- '  hello'  (только справа)

Убрать конкретный символ:

SELECT TRIM('.' FROM '....hello....');   -- 'hello'
SELECT TRIM(BOTH '#' FROM '##hello##'); -- 'hello'

2. SUBSTRING — взять часть

-- с 1-й позиции, 5 символов
SELECT SUBSTRING('hello world', 1, 5);  -- 'hello'

-- с 7-й до конца
SELECT SUBSTRING('hello world', 7);     -- 'world'

-- альтернативный синтаксис
SELECT SUBSTRING('hello world' FROM 1 FOR 5);

3. LEFT / RIGHT

SELECT LEFT('hello world', 5);   -- 'hello'
SELECT RIGHT('hello world', 5);  -- 'world'

4. LENGTH / CHAR_LENGTH

SELECT LENGTH('hello');          -- 5
SELECT LENGTH('привет');         -- 12 (байтах UTF-8) в Postgres
SELECT CHAR_LENGTH('привет');    -- 6 (символов)

Для Unicode используйте CHAR_LENGTH.

5. REPLACE

SELECT REPLACE('hello world', 'world', 'SQL');  -- 'hello SQL'

-- убрать все пробелы
SELECT REPLACE('  hello  world  ', ' ', '');    -- 'helloworld'

6. Практика: почистить email

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

7. Телефон — оставить только цифры

Postgres (regex)

SELECT REGEXP_REPLACE('+7 (495) 123-45-67', '[^0-9]', '', 'g');
-- '74951234567'

MySQL

SELECT REGEXP_REPLACE('+7 (495) 123-45-67', '[^0-9]', '');

8. Первые N символов

-- SKU с 3 буквами префикса
SELECT LEFT(sku, 3) AS category_code FROM products;

9. Убрать «.0» с конца (если число пришло как строка)

SELECT TRIM(TRAILING '.0' FROM '123.0');  -- '123'

10. Поиск и замена с условием

-- username без домена
SELECT SUBSTRING(email FROM 1 FOR POSITION('@' IN email) - 1) AS username
FROM users;

В разных СУБД

Функция Postgres MySQL MSSQL ClickHouse
TRIM TRIM(...) TRIM(...) TRIM(...) trim(...)
SUBSTRING SUBSTRING(s, 1, 5) SUBSTRING(s, 1, 5) SUBSTRING(s, 1, 5) substring(s, 1, 5)
LEFT LEFT(s, n) LEFT(s, n) LEFT(s, n) left(s, n)
LENGTH LENGTH / CHAR_LENGTH LENGTH / CHAR_LENGTH LEN(s) length(s)

Частые ошибки

1. LENGTH vs CHAR_LENGTH на Unicode

В Postgres LENGTH('я') → 2 (байт), CHAR_LENGTH → 1 (символ). Для русского — CHAR_LENGTH.

2. SUBSTRING индекс с 1

В SQL — с 1. В Python — с 0.

3. Не LOWER + TRIM

Сравнение без нормализации находит меньше. Правильно: LOWER(TRIM(col)).

4. REPLACE последовательный

REPLACE(REPLACE(s, 'a', 'b'), 'b', 'c') — может дать неожиданный результат (a→b, потом b→c, итог c, не b).

Связанные темы

FAQ

TRIM убирает табы и newlines?

По умолчанию только пробелы. Для других — TRIM('\t\n' FROM s).

SUBSTRING с отрицательным индексом?

В Postgres работает (с конца). В MySQL — возможны проблемы.

LEFT(s, 0)?

Пустая строка.

Как ускорить на миллионах?

Индекс на LOWER(TRIM(col)): CREATE INDEX idx ON users(LOWER(TRIM(email))).


Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.