SQLstringfunctionstutorial

Что такое LOWER, UPPER, LENGTH в SQL?

Строковые функции — повседневный инструмент SQL: нормализация регистра (LOWER, UPPER), длина строки (LENGTH), обрезка пробелов (TRIM), подстрока (SUBSTRING), замена (REPLACE). Простыми словами: case-insensitive поиск, очистка данных от пробелов и Unicode-нюансы.

13 мин чтенияСправочникSQL · string · functions · tutorial

LOWER, UPPER и LENGTH — это базовые строковые функции в SQL.

Они работают с текстом:

  • LOWER переводит строку в нижний регистр;
  • UPPER переводит строку в верхний регистр;
  • LENGTH считает длину строки.

На первый взгляд кажется: ну и что тут изучать? Сделали буквы маленькими, сделали буквы большими, посчитали символы — готово.

Но в реальной работе с базой данных именно такие функции часто спасают запросы. Пользователь может написать email с большой буквы, вставить пробел в конце, скопировать имя из Excel с лишними символами или ввести телефон в пяти разных форматах.

Строковые функции помогают привести этот хаос к нормальному виду.

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

В учебных примерах данные обычно чистые и красивые.

Email выглядит так:

email
alice@example.com
bob@example.com

А в реальной базе легко встретить такое:

email
Alice@Example.com
bob@example.com
vera@EXAMPLE.com
admin@example.com

Для человека это почти одно и то же: email есть email. Но для базы строки отличаются.

Alice@Example.com и alice@example.com — разные значения, если сравнивать их обычным способом.

Пробел в начале или в конце тоже может сломать поиск. Ты смотришь на значение глазами и думаешь: «ну всё же правильно». А база видит лишний символ и честно говорит: совпадений нет.

Строковые функции нужны, чтобы:

  • приводить email к единому регистру;
  • убирать лишние пробелы;
  • сравнивать строки без учёта регистра;
  • считать длину текста;
  • вырезать часть строки;
  • заменять символы и подстроки;
  • готовить данные для отчётов, поиска и валидации.

Проще говоря, строковые функции — это набор инструментов для уборки в текстовых данных.

LOWER: перевести текст в нижний регистр

LOWER делает все буквы маленькими.

SELECT LOWER('Hello World') AS result;

Результат:

result
hello world

Чаще всего 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;

Результат:

result
HELLO WORLD

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 в нижнем регистре в результате запроса.

Сама таблица не меняется.

Если в таблице было:

email
Alice@Example.com

то после SELECT там всё ещё будет:

email
Alice@Example.com

Чтобы реально изменить данные в таблице, нужен UPDATE.

UPDATE users
SET email = LOWER(email);

Такой запрос уже перезапишет значения в колонке email.

Практический пример: найти пользователя по email

Допустим, есть таблица users.

id email
1 alice@example.com
2 bob@example.com
3 vera@example.com

Пользователь вводит 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');

Результат:

id email
1 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 не всегда помогает искать по результату функции.

Что можно сделать:

  1. Хранить email уже нормализованным. Например, при регистрации сразу приводить его к нижнему регистру.
  2. Создать функциональный индекс. В PostgreSQL можно создать индекс прямо по выражению.
  3. Использовать специальные возможности СУБД. Например, в PostgreSQL есть тип citext, который сравнивает текст без учёта регистра.

Функциональный индекс в PostgreSQL может выглядеть так:

CREATE INDEX users_lower_email_idx
ON users (LOWER(email));

После этого запрос с LOWER(email) получает шанс работать быстрее.

Для новичка главное запомнить: LOWER в WHERE удобен, но на больших таблицах стоит подумать об индексах и нормализации данных.

LENGTH: посчитать длину строки

LENGTH считает длину текста.

SELECT LENGTH('Hello') AS result;

Результат:

result
5

Это удобно для проверок и отчётов.

Например, найти слишком короткие имена:

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;

Результат:

chars_count
5

Для количества байтов в 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;

Результат:

result
hello

Это одна из самых полезных функций при работе с данными из форм, CSV-файлов, Excel и ручного ввода.

Пользователь может случайно ввести:

  alice@example.com 

Глазами это почти незаметно. Но для базы строка с пробелом и строка без пробела — разные значения.

Поэтому email часто чистят так:

UPDATE users
SET email = LOWER(TRIM(email));

Здесь сразу две операции:

  1. TRIM(email) убирает лишние пробелы по краям.
  2. LOWER(...) приводит email к нижнему регистру.

В итоге из грязного значения получается нормальное.

Было Стало
Alice@Example.com alice@example.com
bob@example.com bob@example.com
vera@EXAMPLE.com vera@example.com

LTRIM и RTRIM

Иногда нужно убрать пробелы только с одной стороны.

LTRIM убирает пробелы слева.

SELECT LTRIM('   hello') AS result;

Результат:

result
hello

RTRIM убирает пробелы справа.

SELECT RTRIM('hello   ') AS result;

Результат:

result
hello

Чаще всего хватает обычного TRIM, потому что лишние символы могут приехать с любой стороны.

TRIM может убирать не только пробелы

TRIM умеет убирать не только обычные пробелы, но и указанные символы.

Например:

SELECT TRIM('x' FROM 'xxxhelloxxx') AS result;

Результат:

result
hello

Это значит: убери символ x с начала и конца строки.

Важно: TRIM не удаляет символы внутри строки. Он чистит только края.

SELECT TRIM('x' FROM 'xxhexlloxx') AS result;

Результат:

result
hexllo

Буква 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;

Результат:

result
Hello

Смысл такой:

  • начать с позиции 1;
  • взять 5 символов.

В SQL позиции обычно считаются с 1, а не с 0.

Это важный момент для тех, кто приходит из JavaScript, Python или других языков программирования, где индексация часто начинается с нуля.

Ещё пример:

SELECT SUBSTRING('Hello World' FROM 7) AS result;

Результат:

result
World

Здесь мы говорим: начни с позиции 7 и возьми всё до конца строки.

SUBSTRING в другом синтаксисе

Во многих СУБД можно встретить такой вариант:

SELECT SUBSTRING('Hello World', 1, 5) AS result;

Результат тот же:

result
Hello

Первый вариант чаще выглядит «по-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;

Результат:

domain
example.com

Для новичка регулярные выражения могут выглядеть непривычно. Пока достаточно понять идею: SUBSTRING умеет доставать часть строки не только по позиции, но и по шаблону, если СУБД это поддерживает.

На практике для email в PostgreSQL часто удобнее использовать SPLIT_PART, но это уже отдельная тема.

REPLACE: заменить часть строки

REPLACE заменяет одну подстроку на другую.

SELECT REPLACE('Hello World', 'World', 'SQL') AS result;

Результат:

result
Hello SQL

Формула такая:

REPLACE(source_text, old_text, new_text)

То есть:

  • взять исходную строку;
  • найти старый фрагмент;
  • заменить его на новый.

REPLACE заменяет все вхождения

Важный момент: REPLACE заменяет не первое вхождение, а все.

SELECT REPLACE('aaaa', 'a', 'bb') AS result;

Результат:

result
bbbbbbbb

Каждая буква a превратилась в bb.

Это полезно для массовой чистки данных.

Например, нужно убрать пробелы и дефисы из телефонных номеров.

UPDATE users
SET phone = REPLACE(REPLACE(phone, ' ', ''), '-', '');

Сначала внутренний REPLACE убирает пробелы. Потом внешний REPLACE убирает дефисы.

Если было:

phone
+7 999-123-45-67

после обновления получится:

phone
+79991234567

Конкатенация: склеивание строк

Строки часто нужно не только чистить, но и собирать.

Например, из имени и фамилии получить полное имя.

В 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;

Результат:

result
NULL

То же самое с длиной:

SELECT LENGTH(NULL) AS result;

Результат:

result
NULL

Это логично: если значения нет, то нечего переводить в нижний регистр и нечего измерять.

Но в отчётах это может мешать. Например, нужно склеить имя и фамилию, а фамилия иногда отсутствует.

В 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 появились такие данные.

id email name phone
1 Alice@Example.com Anna +7 999-123-45-67
2 bob@example.com Boris +7 999 222 33 44
3 vera@EXAMPLE.com Vera +7-999-555-66-77

Хотим привести данные к более аккуратному виду:

  • email — без пробелов и в нижнем регистре;
  • name — без пробелов по краям;
  • phone — без пробелов и дефисов.

Запрос:

UPDATE users
SET
  email = LOWER(TRIM(email)),
  name = TRIM(name),
  phone = REPLACE(REPLACE(phone, ' ', ''), '-', '');

После обновления данные станут такими:

id email name phone
1 alice@example.com Anna +79991234567
2 bob@example.com Boris +79992223344
3 vera@example.com Vera +79995556677

Вот зачем строковые функции нужны в реальности. Они превращают «как пользователь ввёл» в «как системе удобно хранить и искать».

Пример для отчёта: красивый вывод

Строковые функции полезны не только для чистки, но и для отчётов.

Есть таблица 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;

Результат:

result
H

Не с 0, как во многих языках программирования.

Используют SUBSTRING, когда есть более понятная функция

Иногда новичок пытается вырезать последние символы через сложный SUBSTRING.

Для таких задач часто есть функции проще: LEFT, RIGHT, SPLIT_PART в PostgreSQL, SUBSTRING_INDEX в MySQL.

SUBSTRING — мощный инструмент, но не всегда самый читаемый.

Забывают, что REPLACE заменяет все совпадения

SELECT REPLACE('aaaa', 'a', 'bb') AS result;

Результат будет не bbaaa и не bba, а:

result
bbbbbbbb

Потому что заменяется каждое вхождение.

Не учитывают 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.

Главная идея: данные в базе редко бывают идеальными. Пользователи вводят текст по-разному, копируют из разных мест, ошибаются с пробелами и регистром. Строковые функции помогают привести всё к единому виду, чтобы поиск, отчёты и проверки работали спокойно и предсказуемо.

Закрепи на практике

Решай задачи в SQL-тренажёре с мгновенной проверкой и подсказками.

Открыть тренажёр