UPPER() и LOWER() в SQL — управление регистром строк

UPPER() переводит строку в верхний регистр, LOWER() — в нижний. Главное применение у аналитика — регистронезависимое сравнение и дедупликация: email, логины и города пользователи пишут по-разному. Важный нюанс: встроенные UPPER/LOWER в SQLite работают только с латиницей и не трогают кириллицу; в PostgreSQL и MySQL регистр зависит от collation базы.

Синтаксис

UPPER(строка) / LOWER(строка)

Примеры использования

Пример 1: Регистронезависимый фильтр

SELECT id, email
FROM users
WHERE LOWER(email) = LOWER('Anna@Mail.RU');

Результат:

id | email
---+-------------
7  | anna@mail.ru

Пример 2: Верхний регистр кода страны

SELECT
  UPPER(country_code) AS cc
FROM users
LIMIT 2;

Результат:

cc
--
RU
KZ

Пример 3: Нормализация для GROUP BY

SELECT
  LOWER(city) AS city,
  COUNT(*) AS cnt
FROM users
GROUP BY LOWER(city)
LIMIT 2;

Результат:

city   | cnt
-------+----
москва | 120
казань | 45
Порешать SQL-задачи в тренажёре →

Типичная ошибка

Встроенные UPPER/LOWER в SQLite обрабатывают только ASCII — кириллица остаётся как есть ('Привет' → 'Привет'). В PostgreSQL и MySQL результат зависит от collation. И главное для больших таблиц: LOWER(col) в WHERE отключает обычный индекс и приводит к full scan — нужен функциональный индекс, ILIKE или CITEXT.

Где спрашивают на собеседовании

Классический вопрос — как сделать регистронезависимое сравнение и дедуп email/логинов. Идёт в паре с TRIM, LIKE/ILIKE и функциональными индексами по LOWER(col).

FAQ: частые вопросы про UPPER / LOWER

Почему LOWER не меняет кириллицу в SQLite?

Встроенные UPPER/LOWER в SQLite покрывают только латиницу, поэтому русские буквы проходят без изменений. Решения: подключить ICU-расширение, нормализовать регистр на стороне приложения, либо использовать PostgreSQL/MySQL, где Unicode обрабатывается через collation.

UPPER(col) в WHERE замедляет запрос?

Да, функция поверх колонки мешает использовать обычный индекс, и база уходит в полное сканирование. Создайте функциональный (expression) индекс по LOWER(col) или используйте регистронезависимое сравнение: ILIKE или тип CITEXT в PostgreSQL.

Есть ли альтернатива LOWER для поиска без учёта регистра?

В PostgreSQL можно сравнивать через ILIKE — он сам игнорирует регистр. В MySQL сравнения по умолчанию регистронезависимы при ci-коллации. В SQLite оператор LIKE нечувствителен к регистру, но только для ASCII-символов.

Задачи в тренажёре по теме

Вопросы с собеседований по теме

Смежные темы SQL

Строковые функции · Агрегации

Другие функции SQL

STRING_AGG · COUNT · SUM OVER · SUBSTR · ROUND · CONCAT

Открыть SQL-тренажёр (565 задач) →