LOWER, UPPER и LENGTH — это базовые строковые функции в SQL.
Они работают с текстом:
LOWER переводит строку в нижний регистр;
UPPER переводит строку в верхний регистр;
LENGTH считает длину строки.
На первый взгляд кажется: ну и что тут изучать? Сделали буквы маленькими, сделали буквы большими, посчитали символы — готово.
Но в реальной работе с базой данных именно такие функции часто спасают запросы. Пользователь может написать email с большой буквы, вставить пробел в конце, скопировать имя из Excel с лишними символами или ввести телефон в пяти разных форматах.
Строковые функции помогают привести этот хаос к нормальному виду.
Зачем нужны строковые функции
В учебных примерах данные обычно чистые и красивые.
Email выглядит так:
А в реальной базе легко встретить такое:
Для человека это почти одно и то же: email есть email. Но для базы строки отличаются.
Alice@Example.com и alice@example.com — разные значения, если сравнивать их обычным способом.
Пробел в начале или в конце тоже может сломать поиск. Ты смотришь на значение глазами и думаешь: «ну всё же правильно». А база видит лишний символ и честно говорит: совпадений нет.
Строковые функции нужны, чтобы:
- приводить email к единому регистру;
- убирать лишние пробелы;
- сравнивать строки без учёта регистра;
- считать длину текста;
- вырезать часть строки;
- заменять символы и подстроки;
- готовить данные для отчётов, поиска и валидации.
Проще говоря, строковые функции — это набор инструментов для уборки в текстовых данных.
LOWER: перевести текст в нижний регистр
LOWER делает все буквы маленькими.
SELECT LOWER('Hello World') AS result;
Результат:
Чаще всего LOWER используют для нормализации email, логинов и других значений, где регистр не должен мешать сравнению.
Например, пользователь вводит email так:
Alice@Example.com
А в базе он хранится так:
alice@example.com
Если сравнить напрямую, можно не найти пользователя. Поэтому часто пишут так:
SELECT
id,
email
FROM users
WHERE LOWER(email) = LOWER('Alice@Example.com');
Смысл простой: мы приводим обе стороны сравнения к нижнему регистру. Теперь неважно, как именно пользователь написал буквы — большими, маленькими или вперемешку.
UPPER: перевести текст в верхний регистр
UPPER делает обратное: переводит буквы в верхний регистр.
SELECT UPPER('Hello World') AS result;
Результат:
UPPER часто используют в отчётах, выгрузках или при подготовке красивого вывода.
Например:
SELECT
id,
UPPER(status) AS status_code
FROM orders;
Если в таблице статусы хранятся как paid, new, cancelled, то в результате можно получить PAID, NEW, CANCELLED.
Но для поиска без учёта регистра чаще используют именно LOWER, потому что удобно договориться: всё важное храним и сравниваем в нижнем регистре.
LOWER и UPPER не меняют данные в таблице
Важно: если ты пишешь такой запрос:
SELECT LOWER(email) AS normalized_email
FROM users;
он только показывает email в нижнем регистре в результате запроса.
Сама таблица не меняется.
Если в таблице было:
то после SELECT там всё ещё будет:
Чтобы реально изменить данные в таблице, нужен UPDATE.
UPDATE users
SET email = LOWER(email);
Такой запрос уже перезапишет значения в колонке email.
Практический пример: найти пользователя по email
Допустим, есть таблица users.
Пользователь вводит email так:
Alice@Example.com
Обычный поиск может не сработать:
SELECT
id,
email
FROM users
WHERE email = 'Alice@Example.com';
А поиск через LOWER сработает:
SELECT
id,
email
FROM users
WHERE LOWER(email) = LOWER('Alice@Example.com');
Результат:
Для начинающего это очень полезный приём: если нужно сравнить текст без учёта регистра, приведи обе стороны к одному виду.
Важный нюанс: функции в WHERE и индексы
Есть подводный камень.
Если на колонке email есть обычный индекс, запрос вида:
SELECT
id,
email
FROM users
WHERE email = 'alice@example.com';
может использовать индекс и быстро найти строку.
А вот такой запрос:
SELECT
id,
email
FROM users
WHERE LOWER(email) = 'alice@example.com';
может оказаться медленнее, потому что база видит не просто колонку email, а выражение LOWER(email).
Обычный индекс по email не всегда помогает искать по результату функции.
Что можно сделать:
- Хранить email уже нормализованным. Например, при регистрации сразу приводить его к нижнему регистру.
- Создать функциональный индекс. В PostgreSQL можно создать индекс прямо по выражению.
- Использовать специальные возможности СУБД. Например, в PostgreSQL есть тип
citext, который сравнивает текст без учёта регистра.
Функциональный индекс в PostgreSQL может выглядеть так:
CREATE INDEX users_lower_email_idx
ON users (LOWER(email));
После этого запрос с LOWER(email) получает шанс работать быстрее.
Для новичка главное запомнить: LOWER в WHERE удобен, но на больших таблицах стоит подумать об индексах и нормализации данных.
LENGTH: посчитать длину строки
LENGTH считает длину текста.
SELECT LENGTH('Hello') AS result;
Результат:
Это удобно для проверок и отчётов.
Например, найти слишком короткие имена:
SELECT
id,
name
FROM users
WHERE LENGTH(name) < 2;
Или найти слишком длинные заголовки:
SELECT
id,
title,
LENGTH(title) AS title_length
FROM posts
WHERE LENGTH(title) > 100;
LENGTH часто используют в задачах на качество данных: проверить, не пустая ли строка, не слишком ли длинный текст, похож ли номер телефона на нормальный по длине.
LENGTH в PostgreSQL и MySQL: важная разница
С LENGTH есть нюанс, о котором новички часто узнают слишком поздно.
В PostgreSQL LENGTH считает символы.
SELECT LENGTH('Hello') AS chars_count;
Результат:
Для количества байтов в PostgreSQL есть отдельная функция OCTET_LENGTH.
SELECT OCTET_LENGTH('Hello') AS bytes_count;
А в MySQL всё иначе: LENGTH возвращает количество байтов, а не символов. Для количества символов в MySQL используют CHAR_LENGTH.
SELECT CHAR_LENGTH('Hello') AS chars_count;
Почему это важно?
Потому что не все символы занимают один байт. В UTF-8 латинские буквы обычно занимают один байт, а многие другие символы могут занимать больше.
Если ты проверяешь ограничение вроде «имя не длиннее 30 символов», то в MySQL лучше использовать CHAR_LENGTH, а не LENGTH.
Более универсальные названия из стандарта SQL:
CHARACTER_LENGTH — длина в символах;
OCTET_LENGTH — длина в байтах.
Если пишешь код, который должен быть понятен и переносим между СУБД, эти названия помогают избежать путаницы.
TRIM: убрать пробелы по краям
TRIM убирает лишние пробелы в начале и в конце строки.
SELECT TRIM(' hello ') AS result;
Результат:
Это одна из самых полезных функций при работе с данными из форм, CSV-файлов, Excel и ручного ввода.
Пользователь может случайно ввести:
alice@example.com
Глазами это почти незаметно. Но для базы строка с пробелом и строка без пробела — разные значения.
Поэтому email часто чистят так:
UPDATE users
SET email = LOWER(TRIM(email));
Здесь сразу две операции:
TRIM(email) убирает лишние пробелы по краям.
LOWER(...) приводит email к нижнему регистру.
В итоге из грязного значения получается нормальное.
LTRIM и RTRIM
Иногда нужно убрать пробелы только с одной стороны.
LTRIM убирает пробелы слева.
SELECT LTRIM(' hello') AS result;
Результат:
RTRIM убирает пробелы справа.
SELECT RTRIM('hello ') AS result;
Результат:
Чаще всего хватает обычного TRIM, потому что лишние символы могут приехать с любой стороны.
TRIM может убирать не только пробелы
TRIM умеет убирать не только обычные пробелы, но и указанные символы.
Например:
SELECT TRIM('x' FROM 'xxxhelloxxx') AS result;
Результат:
Это значит: убери символ x с начала и конца строки.
Важно: TRIM не удаляет символы внутри строки. Он чистит только края.
SELECT TRIM('x' FROM 'xxhexlloxx') AS result;
Результат:
Буква x внутри слова осталась, потому что она не на краю.
Важный нюанс TRIM
Обычно TRIM без дополнительных настроек убирает обычные пробелы по краям строки.
Но в данных могут быть не только обычные пробелы:
- табы;
- переносы строк;
- неразрывные пробелы;
- странные символы после копирования из документов или сайтов.
Для таких случаев простой TRIM может оказаться недостаточным.
В PostgreSQL можно явно указать набор символов, которые нужно убрать:
SELECT TRIM(E' \t\n\r' FROM text_value) AS cleaned_text
FROM raw_data;
Здесь мы просим убрать с краёв обычные пробелы, табы и переносы строк.
SUBSTRING: вырезать часть строки
SUBSTRING достаёт кусок строки.
Например:
SELECT SUBSTRING('Hello World' FROM 1 FOR 5) AS result;
Результат:
Смысл такой:
- начать с позиции
1;
- взять
5 символов.
В SQL позиции обычно считаются с 1, а не с 0.
Это важный момент для тех, кто приходит из JavaScript, Python или других языков программирования, где индексация часто начинается с нуля.
Ещё пример:
SELECT SUBSTRING('Hello World' FROM 7) AS result;
Результат:
Здесь мы говорим: начни с позиции 7 и возьми всё до конца строки.
SUBSTRING в другом синтаксисе
Во многих СУБД можно встретить такой вариант:
SELECT SUBSTRING('Hello World', 1, 5) AS result;
Результат тот же:
Первый вариант чаще выглядит «по-SQL-ному»:
SUBSTRING(text_value FROM start_position FOR length_value)
Второй вариант привычнее тем, кто видел функции в языках программирования:
SUBSTRING(text_value, start_position, length_value)
В учебных задачах важно уметь читать оба варианта.
Пример SUBSTRING: достать домен из email
Допустим, есть email:
alice@example.com
Нужно получить домен:
example.com
Один из вариантов в PostgreSQL — использовать SUBSTRING с регулярным выражением.
SELECT SUBSTRING('alice@example.com' FROM '@(.+)$') AS domain;
Результат:
Для новичка регулярные выражения могут выглядеть непривычно. Пока достаточно понять идею: SUBSTRING умеет доставать часть строки не только по позиции, но и по шаблону, если СУБД это поддерживает.
На практике для email в PostgreSQL часто удобнее использовать SPLIT_PART, но это уже отдельная тема.
REPLACE: заменить часть строки
REPLACE заменяет одну подстроку на другую.
SELECT REPLACE('Hello World', 'World', 'SQL') AS result;
Результат:
Формула такая:
REPLACE(source_text, old_text, new_text)
То есть:
- взять исходную строку;
- найти старый фрагмент;
- заменить его на новый.
REPLACE заменяет все вхождения
Важный момент: REPLACE заменяет не первое вхождение, а все.
SELECT REPLACE('aaaa', 'a', 'bb') AS result;
Результат:
Каждая буква a превратилась в bb.
Это полезно для массовой чистки данных.
Например, нужно убрать пробелы и дефисы из телефонных номеров.
UPDATE users
SET phone = REPLACE(REPLACE(phone, ' ', ''), '-', '');
Сначала внутренний REPLACE убирает пробелы. Потом внешний REPLACE убирает дефисы.
Если было:
после обновления получится:
Конкатенация: склеивание строк
Строки часто нужно не только чистить, но и собирать.
Например, из имени и фамилии получить полное имя.
В PostgreSQL для этого можно использовать оператор ||.
SELECT
first_name || ' ' || last_name AS full_name
FROM users;
Если в таблице есть такие данные:
| first_name |
last_name |
| Anna |
Ivanova |
| Boris |
Petrov |
результат будет таким:
| full_name |
| Anna Ivanova |
| Boris Petrov |
Во многих СУБД есть функция CONCAT.
SELECT
CONCAT(first_name, ' ', last_name) AS full_name
FROM users;
Она делает то же самое: склеивает несколько строк в одну.
NULL в строковых функциях
NULL — это не пустая строка. Это отсутствие значения.
И строковые функции обычно сохраняют NULL.
SELECT LOWER(NULL) AS result;
Результат:
То же самое с длиной:
SELECT LENGTH(NULL) AS result;
Результат:
Это логично: если значения нет, то нечего переводить в нижний регистр и нечего измерять.
Но в отчётах это может мешать. Например, нужно склеить имя и фамилию, а фамилия иногда отсутствует.
В PostgreSQL оператор || с NULL может дать NULL для всего результата.
SELECT
first_name || ' ' || last_name AS full_name
FROM users;
Если last_name равен NULL, итоговое full_name тоже может стать NULL.
Чтобы защититься, используют COALESCE.
SELECT
COALESCE(first_name, '') || ' ' || COALESCE(last_name, '') AS full_name
FROM users;
COALESCE заменяет NULL на запасное значение. В этом примере — на пустую строку.
С CONCAT ситуация может отличаться: во многих СУБД CONCAT обрабатывает NULL мягче и просто игнорирует его. Но поведение лучше проверять в своей базе, особенно если код должен работать в разных СУБД.
Большой пример: чистим пользователей
Допустим, после импорта из CSV в таблице users появились такие данные.
Хотим привести данные к более аккуратному виду:
- email — без пробелов и в нижнем регистре;
- name — без пробелов по краям;
- phone — без пробелов и дефисов.
Запрос:
UPDATE users
SET
email = LOWER(TRIM(email)),
name = TRIM(name),
phone = REPLACE(REPLACE(phone, ' ', ''), '-', '');
После обновления данные станут такими:
Вот зачем строковые функции нужны в реальности. Они превращают «как пользователь ввёл» в «как системе удобно хранить и искать».
Пример для отчёта: красивый вывод
Строковые функции полезны не только для чистки, но и для отчётов.
Есть таблица products.
| id |
name |
category |
sku |
| 1 |
iphone 15 |
phones |
ph-001 |
| 2 |
bosch kettle |
kitchen |
kt-010 |
| 3 |
sql book |
books |
bk-777 |
Хотим вывести название товара в верхнем регистре, категорию в нижнем и длину кода товара.
SELECT
UPPER(name) AS product_name,
LOWER(category) AS category_name,
sku,
LENGTH(sku) AS sku_length
FROM products;
Результат:
| product_name |
category_name |
sku |
sku_length |
| IPHONE 15 |
phones |
ph-001 |
6 |
| BOSCH KETTLE |
kitchen |
kt-010 |
6 |
| SQL BOOK |
books |
bk-777 |
6 |
Таблица не изменилась. Мы просто подготовили удобный вывод.
Частые ошибки новичков
Думают, что LOWER и UPPER меняют таблицу
Запрос:
SELECT LOWER(email)
FROM users;
ничего не обновляет. Он только показывает результат.
Чтобы реально изменить данные, нужен UPDATE.
UPDATE users
SET email = LOWER(email);
Забывают про индекс при LOWER в WHERE
Такой запрос удобен:
SELECT
id,
email
FROM users
WHERE LOWER(email) = LOWER('Alice@Example.com');
Но на большой таблице он может быть медленным без подходящего индекса.
Если поиск по email частый, лучше:
- хранить email уже в нижнем регистре;
- создать функциональный индекс;
- использовать специальный тип или настройку для сравнения без учёта регистра, если СУБД это поддерживает.
Путают длину в символах и байтах
В PostgreSQL LENGTH считает символы.
В MySQL LENGTH считает байты, а CHAR_LENGTH считает символы.
Если работаешь только с английскими буквами, разница может быть незаметна. Но на многоязычных данных она становится важной.
Для проверки длины текста в MySQL обычно безопаснее использовать CHAR_LENGTH.
Ждут, что TRIM уберёт всё подряд
TRIM хорошо убирает обычные пробелы по краям.
Но если в строке таб, перенос строки или необычный пробел, простой TRIM может не помочь.
Тогда нужно явно указать символы для удаления или использовать дополнительные функции очистки.
Забывают, что SUBSTRING считает с 1
В SQL позиции в SUBSTRING обычно начинаются с 1.
SELECT SUBSTRING('Hello' FROM 1 FOR 1) AS result;
Результат:
Не с 0, как во многих языках программирования.
Используют SUBSTRING, когда есть более понятная функция
Иногда новичок пытается вырезать последние символы через сложный SUBSTRING.
Для таких задач часто есть функции проще: LEFT, RIGHT, SPLIT_PART в PostgreSQL, SUBSTRING_INDEX в MySQL.
SUBSTRING — мощный инструмент, но не всегда самый читаемый.
Забывают, что REPLACE заменяет все совпадения
SELECT REPLACE('aaaa', 'a', 'bb') AS result;
Результат будет не bbaaa и не bba, а:
Потому что заменяется каждое вхождение.
Не учитывают NULL
LOWER(NULL), UPPER(NULL), LENGTH(NULL) обычно возвращают NULL.
Если нужно подставить пустую строку, используй COALESCE.
SELECT
LOWER(COALESCE(email, '')) AS normalized_email
FROM users;
Короткая шпаргалка
| Функция |
Что делает |
Пример |
LOWER |
Переводит текст в нижний регистр |
LOWER('Hello') |
UPPER |
Переводит текст в верхний регистр |
UPPER('Hello') |
LENGTH |
Считает длину строки |
LENGTH('Hello') |
CHAR_LENGTH |
Считает символы, особенно полезно в MySQL |
CHAR_LENGTH('Hello') |
OCTET_LENGTH |
Считает байты |
OCTET_LENGTH('Hello') |
TRIM |
Убирает символы по краям строки |
TRIM(' hello ') |
LTRIM |
Убирает пробелы слева |
LTRIM(' hello') |
RTRIM |
Убирает пробелы справа |
RTRIM('hello ') |
SUBSTRING |
Достаёт часть строки |
SUBSTRING('Hello' FROM 1 FOR 2) |
REPLACE |
Заменяет все вхождения |
REPLACE('Hello', 'H', 'J') |
CONCAT |
Склеивает строки |
CONCAT('Hello', ' ', 'SQL') |
Мини-резюме
LOWER, UPPER и LENGTH — базовые функции для работы с текстом в SQL.
LOWER приводит строку к нижнему регистру, UPPER — к верхнему, LENGTH считает длину.
Рядом с ними почти всегда идут другие полезные функции:
TRIM убирает лишние пробелы по краям;
SUBSTRING достаёт часть строки;
REPLACE заменяет один фрагмент текста на другой;
CONCAT и || склеивают строки;
COALESCE помогает аккуратно работать с NULL.
Главная идея: данные в базе редко бывают идеальными. Пользователи вводят текст по-разному, копируют из разных мест, ошибаются с пробелами и регистром. Строковые функции помогают привести всё к единому виду, чтобы поиск, отчёты и проверки работали спокойно и предсказуемо.
LOWER,UPPERиLENGTH— это базовые строковые функции в SQL.Они работают с текстом:
LOWERпереводит строку в нижний регистр;UPPERпереводит строку в верхний регистр;LENGTHсчитает длину строки.На первый взгляд кажется: ну и что тут изучать? Сделали буквы маленькими, сделали буквы большими, посчитали символы — готово.
Но в реальной работе с базой данных именно такие функции часто спасают запросы. Пользователь может написать email с большой буквы, вставить пробел в конце, скопировать имя из Excel с лишними символами или ввести телефон в пяти разных форматах.
Строковые функции помогают привести этот хаос к нормальному виду.
Зачем нужны строковые функции
В учебных примерах данные обычно чистые и красивые.
Email выглядит так:
А в реальной базе легко встретить такое:
Для человека это почти одно и то же: email есть email. Но для базы строки отличаются.
Alice@Example.comиalice@example.com— разные значения, если сравнивать их обычным способом.Пробел в начале или в конце тоже может сломать поиск. Ты смотришь на значение глазами и думаешь: «ну всё же правильно». А база видит лишний символ и честно говорит: совпадений нет.
Строковые функции нужны, чтобы:
Проще говоря, строковые функции — это набор инструментов для уборки в текстовых данных.
LOWER: перевести текст в нижний регистр
LOWERделает все буквы маленькими.SELECT LOWER('Hello World') AS result;Результат:
Чаще всего
LOWERиспользуют для нормализации email, логинов и других значений, где регистр не должен мешать сравнению.Например, пользователь вводит email так:
А в базе он хранится так:
Если сравнить напрямую, можно не найти пользователя. Поэтому часто пишут так:
SELECT id, email FROM users WHERE LOWER(email) = LOWER('Alice@Example.com');Смысл простой: мы приводим обе стороны сравнения к нижнему регистру. Теперь неважно, как именно пользователь написал буквы — большими, маленькими или вперемешку.
UPPER: перевести текст в верхний регистр
UPPERделает обратное: переводит буквы в верхний регистр.SELECT UPPER('Hello World') AS result;Результат:
UPPERчасто используют в отчётах, выгрузках или при подготовке красивого вывода.Например:
SELECT id, UPPER(status) AS status_code FROM orders;Если в таблице статусы хранятся как
paid,new,cancelled, то в результате можно получитьPAID,NEW,CANCELLED.Но для поиска без учёта регистра чаще используют именно
LOWER, потому что удобно договориться: всё важное храним и сравниваем в нижнем регистре.LOWER и UPPER не меняют данные в таблице
Важно: если ты пишешь такой запрос:
SELECT LOWER(email) AS normalized_email FROM users;он только показывает email в нижнем регистре в результате запроса.
Сама таблица не меняется.
Если в таблице было:
то после
SELECTтам всё ещё будет:Чтобы реально изменить данные в таблице, нужен
UPDATE.UPDATE users SET email = LOWER(email);Такой запрос уже перезапишет значения в колонке
email.Практический пример: найти пользователя по email
Допустим, есть таблица
users.Пользователь вводит email так:
Обычный поиск может не сработать:
SELECT id, email FROM users WHERE email = 'Alice@Example.com';А поиск через
LOWERсработает:SELECT id, email FROM users WHERE LOWER(email) = LOWER('Alice@Example.com');Результат:
Для начинающего это очень полезный приём: если нужно сравнить текст без учёта регистра, приведи обе стороны к одному виду.
Важный нюанс: функции в WHERE и индексы
Есть подводный камень.
Если на колонке
emailесть обычный индекс, запрос вида:SELECT id, email FROM users WHERE email = 'alice@example.com';может использовать индекс и быстро найти строку.
А вот такой запрос:
SELECT id, email FROM users WHERE LOWER(email) = 'alice@example.com';может оказаться медленнее, потому что база видит не просто колонку
email, а выражениеLOWER(email).Обычный индекс по
emailне всегда помогает искать по результату функции.Что можно сделать:
citext, который сравнивает текст без учёта регистра.Функциональный индекс в PostgreSQL может выглядеть так:
CREATE INDEX users_lower_email_idx ON users (LOWER(email));После этого запрос с
LOWER(email)получает шанс работать быстрее.Для новичка главное запомнить:
LOWERвWHEREудобен, но на больших таблицах стоит подумать об индексах и нормализации данных.LENGTH: посчитать длину строки
LENGTHсчитает длину текста.SELECT LENGTH('Hello') AS result;Результат:
Это удобно для проверок и отчётов.
Например, найти слишком короткие имена:
SELECT id, name FROM users WHERE LENGTH(name) < 2;Или найти слишком длинные заголовки:
SELECT id, title, LENGTH(title) AS title_length FROM posts WHERE LENGTH(title) > 100;LENGTHчасто используют в задачах на качество данных: проверить, не пустая ли строка, не слишком ли длинный текст, похож ли номер телефона на нормальный по длине.LENGTH в PostgreSQL и MySQL: важная разница
С
LENGTHесть нюанс, о котором новички часто узнают слишком поздно.В PostgreSQL
LENGTHсчитает символы.SELECT LENGTH('Hello') AS chars_count;Результат:
Для количества байтов в PostgreSQL есть отдельная функция
OCTET_LENGTH.SELECT OCTET_LENGTH('Hello') AS bytes_count;А в MySQL всё иначе:
LENGTHвозвращает количество байтов, а не символов. Для количества символов в MySQL используютCHAR_LENGTH.SELECT CHAR_LENGTH('Hello') AS chars_count;Почему это важно?
Потому что не все символы занимают один байт. В UTF-8 латинские буквы обычно занимают один байт, а многие другие символы могут занимать больше.
Если ты проверяешь ограничение вроде «имя не длиннее 30 символов», то в MySQL лучше использовать
CHAR_LENGTH, а неLENGTH.Более универсальные названия из стандарта SQL:
CHARACTER_LENGTH— длина в символах;OCTET_LENGTH— длина в байтах.Если пишешь код, который должен быть понятен и переносим между СУБД, эти названия помогают избежать путаницы.
TRIM: убрать пробелы по краям
TRIMубирает лишние пробелы в начале и в конце строки.SELECT TRIM(' hello ') AS result;Результат:
Это одна из самых полезных функций при работе с данными из форм, CSV-файлов, Excel и ручного ввода.
Пользователь может случайно ввести:
Глазами это почти незаметно. Но для базы строка с пробелом и строка без пробела — разные значения.
Поэтому email часто чистят так:
UPDATE users SET email = LOWER(TRIM(email));Здесь сразу две операции:
TRIM(email)убирает лишние пробелы по краям.LOWER(...)приводит email к нижнему регистру.В итоге из грязного значения получается нормальное.
LTRIM и RTRIM
Иногда нужно убрать пробелы только с одной стороны.
LTRIMубирает пробелы слева.SELECT LTRIM(' hello') AS result;Результат:
RTRIMубирает пробелы справа.SELECT RTRIM('hello ') AS result;Результат:
Чаще всего хватает обычного
TRIM, потому что лишние символы могут приехать с любой стороны.TRIM может убирать не только пробелы
TRIMумеет убирать не только обычные пробелы, но и указанные символы.Например:
SELECT TRIM('x' FROM 'xxxhelloxxx') AS result;Результат:
Это значит: убери символ
xс начала и конца строки.Важно:
TRIMне удаляет символы внутри строки. Он чистит только края.SELECT TRIM('x' FROM 'xxhexlloxx') AS result;Результат:
Буква
xвнутри слова осталась, потому что она не на краю.Важный нюанс TRIM
Обычно
TRIMбез дополнительных настроек убирает обычные пробелы по краям строки.Но в данных могут быть не только обычные пробелы:
Для таких случаев простой
TRIMможет оказаться недостаточным.В PostgreSQL можно явно указать набор символов, которые нужно убрать:
SELECT TRIM(E' \t\n\r' FROM text_value) AS cleaned_text FROM raw_data;Здесь мы просим убрать с краёв обычные пробелы, табы и переносы строк.
SUBSTRING: вырезать часть строки
SUBSTRINGдостаёт кусок строки.Например:
SELECT SUBSTRING('Hello World' FROM 1 FOR 5) AS result;Результат:
Смысл такой:
1;5символов.В SQL позиции обычно считаются с
1, а не с0.Это важный момент для тех, кто приходит из JavaScript, Python или других языков программирования, где индексация часто начинается с нуля.
Ещё пример:
SELECT SUBSTRING('Hello World' FROM 7) AS result;Результат:
Здесь мы говорим: начни с позиции
7и возьми всё до конца строки.SUBSTRING в другом синтаксисе
Во многих СУБД можно встретить такой вариант:
SELECT SUBSTRING('Hello World', 1, 5) AS result;Результат тот же:
Первый вариант чаще выглядит «по-SQL-ному»:
SUBSTRING(text_value FROM start_position FOR length_value)Второй вариант привычнее тем, кто видел функции в языках программирования:
SUBSTRING(text_value, start_position, length_value)В учебных задачах важно уметь читать оба варианта.
Пример SUBSTRING: достать домен из email
Допустим, есть email:
Нужно получить домен:
Один из вариантов в PostgreSQL — использовать
SUBSTRINGс регулярным выражением.SELECT SUBSTRING('alice@example.com' FROM '@(.+)$') AS domain;Результат:
Для новичка регулярные выражения могут выглядеть непривычно. Пока достаточно понять идею:
SUBSTRINGумеет доставать часть строки не только по позиции, но и по шаблону, если СУБД это поддерживает.На практике для email в PostgreSQL часто удобнее использовать
SPLIT_PART, но это уже отдельная тема.REPLACE: заменить часть строки
REPLACEзаменяет одну подстроку на другую.SELECT REPLACE('Hello World', 'World', 'SQL') AS result;Результат:
Формула такая:
То есть:
REPLACE заменяет все вхождения
Важный момент:
REPLACEзаменяет не первое вхождение, а все.SELECT REPLACE('aaaa', 'a', 'bb') AS result;Результат:
Каждая буква
aпревратилась вbb.Это полезно для массовой чистки данных.
Например, нужно убрать пробелы и дефисы из телефонных номеров.
UPDATE users SET phone = REPLACE(REPLACE(phone, ' ', ''), '-', '');Сначала внутренний
REPLACEубирает пробелы. Потом внешнийREPLACEубирает дефисы.Если было:
после обновления получится:
Конкатенация: склеивание строк
Строки часто нужно не только чистить, но и собирать.
Например, из имени и фамилии получить полное имя.
В PostgreSQL для этого можно использовать оператор
||.SELECT first_name || ' ' || last_name AS full_name FROM users;Если в таблице есть такие данные:
результат будет таким:
Во многих СУБД есть функция
CONCAT.SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;Она делает то же самое: склеивает несколько строк в одну.
NULL в строковых функциях
NULL— это не пустая строка. Это отсутствие значения.И строковые функции обычно сохраняют
NULL.SELECT LOWER(NULL) AS result;Результат:
То же самое с длиной:
SELECT LENGTH(NULL) AS result;Результат:
Это логично: если значения нет, то нечего переводить в нижний регистр и нечего измерять.
Но в отчётах это может мешать. Например, нужно склеить имя и фамилию, а фамилия иногда отсутствует.
В PostgreSQL оператор
||сNULLможет датьNULLдля всего результата.SELECT first_name || ' ' || last_name AS full_name FROM users;Если
last_nameравенNULL, итоговоеfull_nameтоже может статьNULL.Чтобы защититься, используют
COALESCE.SELECT COALESCE(first_name, '') || ' ' || COALESCE(last_name, '') AS full_name FROM users;COALESCEзаменяетNULLна запасное значение. В этом примере — на пустую строку.С
CONCATситуация может отличаться: во многих СУБДCONCATобрабатываетNULLмягче и просто игнорирует его. Но поведение лучше проверять в своей базе, особенно если код должен работать в разных СУБД.Большой пример: чистим пользователей
Допустим, после импорта из CSV в таблице
usersпоявились такие данные.Хотим привести данные к более аккуратному виду:
Запрос:
UPDATE users SET email = LOWER(TRIM(email)), name = TRIM(name), phone = REPLACE(REPLACE(phone, ' ', ''), '-', '');После обновления данные станут такими:
Вот зачем строковые функции нужны в реальности. Они превращают «как пользователь ввёл» в «как системе удобно хранить и искать».
Пример для отчёта: красивый вывод
Строковые функции полезны не только для чистки, но и для отчётов.
Есть таблица
products.Хотим вывести название товара в верхнем регистре, категорию в нижнем и длину кода товара.
SELECT UPPER(name) AS product_name, LOWER(category) AS category_name, sku, LENGTH(sku) AS sku_length FROM products;Результат:
Таблица не изменилась. Мы просто подготовили удобный вывод.
Частые ошибки новичков
Думают, что LOWER и UPPER меняют таблицу
Запрос:
SELECT LOWER(email) FROM users;ничего не обновляет. Он только показывает результат.
Чтобы реально изменить данные, нужен
UPDATE.UPDATE users SET email = LOWER(email);Забывают про индекс при LOWER в WHERE
Такой запрос удобен:
SELECT id, email FROM users WHERE LOWER(email) = LOWER('Alice@Example.com');Но на большой таблице он может быть медленным без подходящего индекса.
Если поиск по email частый, лучше:
Путают длину в символах и байтах
В PostgreSQL
LENGTHсчитает символы.В MySQL
LENGTHсчитает байты, аCHAR_LENGTHсчитает символы.Если работаешь только с английскими буквами, разница может быть незаметна. Но на многоязычных данных она становится важной.
Для проверки длины текста в MySQL обычно безопаснее использовать
CHAR_LENGTH.Ждут, что TRIM уберёт всё подряд
TRIMхорошо убирает обычные пробелы по краям.Но если в строке таб, перенос строки или необычный пробел, простой
TRIMможет не помочь.Тогда нужно явно указать символы для удаления или использовать дополнительные функции очистки.
Забывают, что SUBSTRING считает с 1
В SQL позиции в
SUBSTRINGобычно начинаются с1.SELECT SUBSTRING('Hello' FROM 1 FOR 1) AS result;Результат:
Не с
0, как во многих языках программирования.Используют SUBSTRING, когда есть более понятная функция
Иногда новичок пытается вырезать последние символы через сложный
SUBSTRING.Для таких задач часто есть функции проще:
LEFT,RIGHT,SPLIT_PARTв PostgreSQL,SUBSTRING_INDEXв MySQL.SUBSTRING— мощный инструмент, но не всегда самый читаемый.Забывают, что REPLACE заменяет все совпадения
SELECT REPLACE('aaaa', 'a', 'bb') AS result;Результат будет не
bbaaaи неbba, а:Потому что заменяется каждое вхождение.
Не учитывают NULL
LOWER(NULL),UPPER(NULL),LENGTH(NULL)обычно возвращаютNULL.Если нужно подставить пустую строку, используй
COALESCE.SELECT LOWER(COALESCE(email, '')) AS normalized_email FROM users;Короткая шпаргалка
LOWERLOWER('Hello')UPPERUPPER('Hello')LENGTHLENGTH('Hello')CHAR_LENGTHCHAR_LENGTH('Hello')OCTET_LENGTHOCTET_LENGTH('Hello')TRIMTRIM(' hello ')LTRIMLTRIM(' hello')RTRIMRTRIM('hello ')SUBSTRINGSUBSTRING('Hello' FROM 1 FOR 2)REPLACEREPLACE('Hello', 'H', 'J')CONCATCONCAT('Hello', ' ', 'SQL')Мини-резюме
LOWER,UPPERиLENGTH— базовые функции для работы с текстом в SQL.LOWERприводит строку к нижнему регистру,UPPER— к верхнему,LENGTHсчитает длину.Рядом с ними почти всегда идут другие полезные функции:
TRIMубирает лишние пробелы по краям;SUBSTRINGдостаёт часть строки;REPLACEзаменяет один фрагмент текста на другой;CONCATи||склеивают строки;COALESCEпомогает аккуратно работать сNULL.Главная идея: данные в базе редко бывают идеальными. Пользователи вводят текст по-разному, копируют из разных мест, ошибаются с пробелами и регистром. Строковые функции помогают привести всё к единому виду, чтобы поиск, отчёты и проверки работали спокойно и предсказуемо.