Tá an t-alt seo i Rúisis faoi láthair — tá an t-aistriúchán Béarla ar siúl.
INITCAP — это функция PostgreSQL, которая делает первую букву каждого слова заглавной, а остальные буквы строчными. Это удобно для приведения имён, городов и названий к единому виду title-case, но у функции есть неочевидные ограничения, о которых стоит знать заранее.
INITCAP решает узкую задачу — презентационную нормализацию регистра, а не каноничное написание имени. Поэтому в запросе важно видеть, что initcap(name) отдаёт значение «для показа», а не утверждает юридически точную форму фамилии. Если вы прогоняете данные через эту функцию в отчётах, проверках качества или разовых чистках, вынесите её в явный слой — view, generated column или staging-преобразование, — где правило приведения регистра можно протестировать на пограничных именах и переиспользовать, а не дублировать в каждом запросе.
Что делает INITCAP
INITCAP берёт строку, разбивает её на слова и для каждого слова поднимает первую букву в верхний регистр, а все остальные опускает в нижний. Словом считается любая последовательность буквенно-цифровых символов, а границей слова — любой небуквенно-цифровой символ (пробел, точка, дефис, апостроф и так далее).
SELECT initcap('john DOE');
SELECT initcap('HELLO world');
SELECT initcap('order #42 paid');
Обратите внимание: исходный регистр середины слова не сохраняется. INITCAP всегда нормализует слово к виду «первая заглавная, дальше строчные», поэтому 'McDONALD' превратится в 'Mcdonald'.
Нормализация имён и городов
Типичный сценарий — данные пришли из формы или импорта в произвольном регистре, и их нужно показать аккуратно.
SELECT id, initcap(name) AS display_name
FROM users
ORDER BY display_name;
SELECT initcap(country) AS country, count(*) AS users
FROM users
GROUP BY initcap(country)
ORDER BY users DESC;
Можно сразу записать приведённое значение обратно, если хотите хранить данные в чистом виде:
UPDATE users
SET name = initcap(name)
WHERE name <> initcap(name);
Где INITCAP ломается
Главная ловушка в том, что INITCAP считает границей слова любой неалфавитно-цифровой символ. Для реальных имён это часто неверно:
- апостроф начинает «новое слово», поэтому буква после него становится заглавной;
- дефисы и апострофы внутри имени тоже считаются границами слов;
- внутренние заглавные (как в
McDonald) теряются — они опускаются в нижний регистр.
SELECT initcap('o''brien');
SELECT initcap('jean-luc PICARD');
SELECT initcap('mcdonald');
Ловушка: INITCAP не знает культурных правил вроде McDonald, van der Berg или DeShawn. После апострофа и дефиса он всегда ставит заглавную, а средние заглавные внутри слова теряет. Для брендов и фамилий с особым написанием полагаться на INITCAP нельзя — храните каноничную форму отдельно.
Второй нюанс — локаль и Unicode. PostgreSQL приводит регистр согласно локали базы данных, и для некоторых пар (например, турецкая i/I) результат может отличаться от ожидаемого. Для ASCII-имён всё предсказуемо, но для многоязычных данных проверяйте поведение в своей локали.
Если INITCAP портит только отдельные записи, не пишите его результат на всю таблицу — отберите проблемные строки и поправьте их точечно:
UPDATE users
SET name = initcap(name)
WHERE name <> initcap(name)
AND name !~ '[''-]';
INITCAP в MySQL: эмуляция
В MySQL функции INITCAP нет. Для одного слова её легко собрать из UPPER, LOWER и SUBSTRING:
SELECT CONCAT(
UPPER(SUBSTRING(name, 1, 1)),
LOWER(SUBSTRING(name, 2))
) AS display_name
FROM users;
Для многословных строк такого выражения мало — нужно обработать каждое слово. На практике это решают пользовательской функцией, которая идёт по строке и поднимает букву после каждого пробела, либо выносят логику в приложение. ClickHouse тоже не имеет INITCAP, но предлагает upperUTF8, lowerUTF8 и substring, из которых строится та же эмуляция.
Перед переносом этой эмуляции между PostgreSQL, MySQL и ClickHouse прогоните initcap на маленькой таблице с теми самыми крайними значениями, на которых функция и спотыкается: имена с апострофом (o'brien) и дефисом (jean-luc), внутренние заглавные (mcdonald), пустая строка, NULL и не-ASCII буквы. На «чистых» односложных именах все три движка совпадут, а расходятся они ровно на этих пограничных строках — поэтому держите их в тесте именно для приведения регистра, а не только для итогового отчёта.
И последнее про производительность: initcap(name) в условии WHERE или GROUP BY оборачивает колонку функцией, а значит обычный индекс по name не используется и каждая строка нормализуется заново. На большой таблице это заметно: либо храните уже приведённое значение в отдельной колонке (например, generated column) и индексируйте её, либо чистите регистр разово через UPDATE, как показано выше, а не на каждом чтении.
Короткий итог: в PostgreSQL INITCAP отлично подходит для быстрой нормализации простых ASCII-строк, но не доверяйте ему фамилии с апострофами, дефисами и внутренними заглавными; в MySQL и ClickHouse того же эффекта добиваются вручную через UPPER + LOWER + SUBSTRING.
INITCAP— это функция PostgreSQL, которая делает первую букву каждого слова заглавной, а остальные буквы строчными. Это удобно для приведения имён, городов и названий к единому виду title-case, но у функции есть неочевидные ограничения, о которых стоит знать заранее.INITCAPрешает узкую задачу — презентационную нормализацию регистра, а не каноничное написание имени. Поэтому в запросе важно видеть, чтоinitcap(name)отдаёт значение «для показа», а не утверждает юридически точную форму фамилии. Если вы прогоняете данные через эту функцию в отчётах, проверках качества или разовых чистках, вынесите её в явный слой — view, generated column или staging-преобразование, — где правило приведения регистра можно протестировать на пограничных именах и переиспользовать, а не дублировать в каждом запросе.Что делает INITCAP
INITCAPберёт строку, разбивает её на слова и для каждого слова поднимает первую букву в верхний регистр, а все остальные опускает в нижний. Словом считается любая последовательность буквенно-цифровых символов, а границей слова — любой небуквенно-цифровой символ (пробел, точка, дефис, апостроф и так далее).SELECT initcap('john DOE'); -- John Doe SELECT initcap('HELLO world'); -- Hello World SELECT initcap('order #42 paid'); -- Order #42 PaidОбратите внимание: исходный регистр середины слова не сохраняется.
INITCAPвсегда нормализует слово к виду «первая заглавная, дальше строчные», поэтому'McDONALD'превратится в'Mcdonald'.Нормализация имён и городов
Типичный сценарий — данные пришли из формы или импорта в произвольном регистре, и их нужно показать аккуратно.
-- Tidy up names captured in mixed or all-caps form SELECT id, initcap(name) AS display_name FROM users ORDER BY display_name; -- Normalize country labels for a report SELECT initcap(country) AS country, count(*) AS users FROM users GROUP BY initcap(country) ORDER BY users DESC;Можно сразу записать приведённое значение обратно, если хотите хранить данные в чистом виде:
-- One-off cleanup of inconsistent name casing UPDATE users SET name = initcap(name) WHERE name <> initcap(name);Где INITCAP ломается
Главная ловушка в том, что
INITCAPсчитает границей слова любой неалфавитно-цифровой символ. Для реальных имён это часто неверно:McDonald) теряются — они опускаются в нижний регистр.SELECT initcap('o''brien'); -- O'Brien (B capitalized after the quote) SELECT initcap('jean-luc PICARD'); -- Jean-Luc Picard SELECT initcap('mcdonald'); -- Mcdonald (not McDonald)Второй нюанс — локаль и Unicode. PostgreSQL приводит регистр согласно локали базы данных, и для некоторых пар (например, турецкая
i/I) результат может отличаться от ожидаемого. Для ASCII-имён всё предсказуемо, но для многоязычных данных проверяйте поведение в своей локали.Если
INITCAPпортит только отдельные записи, не пишите его результат на всю таблицу — отберите проблемные строки и поправьте их точечно:-- Apply initcap only where it is safe: skip names with apostrophes or hyphens UPDATE users SET name = initcap(name) WHERE name <> initcap(name) AND name !~ '[''-]';INITCAP в MySQL: эмуляция
В MySQL функции
INITCAPнет. Для одного слова её легко собрать изUPPER,LOWERиSUBSTRING:-- MySQL: capitalize only the first letter of a single word SELECT CONCAT( UPPER(SUBSTRING(name, 1, 1)), LOWER(SUBSTRING(name, 2)) ) AS display_name FROM users;Для многословных строк такого выражения мало — нужно обработать каждое слово. На практике это решают пользовательской функцией, которая идёт по строке и поднимает букву после каждого пробела, либо выносят логику в приложение. ClickHouse тоже не имеет
INITCAP, но предлагаетupperUTF8,lowerUTF8иsubstring, из которых строится та же эмуляция.Перед переносом этой эмуляции между PostgreSQL, MySQL и ClickHouse прогоните
initcapна маленькой таблице с теми самыми крайними значениями, на которых функция и спотыкается: имена с апострофом (o'brien) и дефисом (jean-luc), внутренние заглавные (mcdonald), пустая строка, NULL и не-ASCII буквы. На «чистых» односложных именах все три движка совпадут, а расходятся они ровно на этих пограничных строках — поэтому держите их в тесте именно для приведения регистра, а не только для итогового отчёта.И последнее про производительность:
initcap(name)в условииWHEREилиGROUP BYоборачивает колонку функцией, а значит обычный индекс поnameне используется и каждая строка нормализуется заново. На большой таблице это заметно: либо храните уже приведённое значение в отдельной колонке (например, generated column) и индексируйте её, либо чистите регистр разово черезUPDATE, как показано выше, а не на каждом чтении.Короткий итог: в PostgreSQL
INITCAPотлично подходит для быстрой нормализации простых ASCII-строк, но не доверяйте ему фамилии с апострофами, дефисами и внутренними заглавными; в MySQL и ClickHouse того же эффекта добиваются вручную черезUPPER+LOWER+SUBSTRING.