INITCAP es una funcion de PostgreSQL que pone en mayuscula la primera letra de cada palabra y el resto en minuscula. Es util para normalizar nombres, ciudades y etiquetas a un title-case uniforme, pero trae algunas limitaciones poco obvias que conviene conocer de antemano.
Que hace INITCAP
INITCAP toma una cadena, la divide en palabras y, para cada palabra, sube la primera letra a mayuscula y fuerza el resto a minuscula. Una palabra es cualquier secuencia de caracteres alfanumericos; un limite de palabra es cualquier caracter no alfanumerico (espacio, punto, guion, apostrofo, etc.).
SELECT initcap('john DOE');
SELECT initcap('HELLO world');
SELECT initcap('order #42 paid');
Fijate en que no se conserva el caso interior original. INITCAP siempre normaliza cada palabra a "primera en mayuscula, el resto en minuscula", asi que 'McDONALD' se convierte en 'Mcdonald'.
Normalizar nombres y ciudades
El caso clasico son datos que llegaron de un formulario o una importacion con un caso arbitrario y que hay que mostrar de forma prolija.
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;
Tambien puedes guardar de vuelta el valor normalizado si quieres datos limpios en reposo:
UPDATE users
SET name = initcap(name)
WHERE name <> initcap(name);
Donde falla INITCAP
La gran trampa es que INITCAP trata cualquier caracter no alfanumerico como limite de palabra. Para nombres reales eso suele estar mal:
- un apostrofo inicia una "palabra nueva", asi que la letra que le sigue se pone en mayuscula;
- los guiones y apostrofos dentro de un nombre se tratan todos como separadores;
- las mayusculas interiores (como en
McDonald) se pierden: bajan a minuscula.
SELECT initcap('o''brien');
SELECT initcap('jean-luc PICARD');
SELECT initcap('mcdonald');
Gotcha: INITCAP no conoce reglas culturales como McDonald, van der Berg o DeShawn. Siempre pone mayuscula tras un apostrofo o un guion, y pierde las mayusculas interiores de una palabra. Para marcas y apellidos con escritura especial, no confies en INITCAP: guarda la forma canonica por separado.
El segundo matiz es el locale y Unicode. PostgreSQL cambia el caso segun el locale de la base de datos, y para algunos pares (la i/I turca, por ejemplo) el resultado puede diferir de lo esperado. Los nombres ASCII son predecibles, pero con datos multilingues verifica el comportamiento en tu propio locale.
Si INITCAP solo estropea unas pocas filas, no escribas su resultado en toda la tabla: selecciona las filas problematicas y corrige el resto en su sitio:
UPDATE users
SET name = initcap(name)
WHERE name <> initcap(name)
AND name !~ '[''-]';
INITCAP en MySQL: emulacion
MySQL no tiene INITCAP. Para una sola palabra es facil armarlo con UPPER, LOWER y SUBSTRING:
SELECT CONCAT(
UPPER(SUBSTRING(name, 1, 1)),
LOWER(SUBSTRING(name, 2))
) AS display_name
FROM users;
Para cadenas de varias palabras esa expresion no basta: hay que procesar cada palabra. En la practica los equipos lo resuelven con una funcion almacenada que recorre la cadena y pone en mayuscula la letra tras cada espacio, o llevan la logica a la capa de aplicacion. ClickHouse tampoco tiene INITCAP, pero ofrece upperUTF8, lowerUTF8 y substring, con los que se construye la misma emulacion.
En resumen: en PostgreSQL INITCAP es estupendo para normalizar rapido cadenas ASCII simples, pero no le confies apellidos con apostrofos, guiones o mayusculas interiores; en MySQL y ClickHouse logras el mismo efecto a mano con UPPER + LOWER + SUBSTRING.
INITCAPes una funcion de PostgreSQL que pone en mayuscula la primera letra de cada palabra y el resto en minuscula. Es util para normalizar nombres, ciudades y etiquetas a un title-case uniforme, pero trae algunas limitaciones poco obvias que conviene conocer de antemano.Que hace INITCAP
INITCAPtoma una cadena, la divide en palabras y, para cada palabra, sube la primera letra a mayuscula y fuerza el resto a minuscula. Una palabra es cualquier secuencia de caracteres alfanumericos; un limite de palabra es cualquier caracter no alfanumerico (espacio, punto, guion, apostrofo, etc.).SELECT initcap('john DOE'); -- John Doe SELECT initcap('HELLO world'); -- Hello World SELECT initcap('order #42 paid'); -- Order #42 PaidFijate en que no se conserva el caso interior original.
INITCAPsiempre normaliza cada palabra a "primera en mayuscula, el resto en minuscula", asi que'McDONALD'se convierte en'Mcdonald'.Normalizar nombres y ciudades
El caso clasico son datos que llegaron de un formulario o una importacion con un caso arbitrario y que hay que mostrar de forma prolija.
-- 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;Tambien puedes guardar de vuelta el valor normalizado si quieres datos limpios en reposo:
-- One-off cleanup of inconsistent name casing UPDATE users SET name = initcap(name) WHERE name <> initcap(name);Donde falla INITCAP
La gran trampa es que
INITCAPtrata cualquier caracter no alfanumerico como limite de palabra. Para nombres reales eso suele estar mal:McDonald) se pierden: bajan a minuscula.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)El segundo matiz es el locale y Unicode. PostgreSQL cambia el caso segun el locale de la base de datos, y para algunos pares (la
i/Iturca, por ejemplo) el resultado puede diferir de lo esperado. Los nombres ASCII son predecibles, pero con datos multilingues verifica el comportamiento en tu propio locale.Si
INITCAPsolo estropea unas pocas filas, no escribas su resultado en toda la tabla: selecciona las filas problematicas y corrige el resto en su sitio:-- 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 en MySQL: emulacion
MySQL no tiene
INITCAP. Para una sola palabra es facil armarlo conUPPER,LOWERySUBSTRING:-- 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;Para cadenas de varias palabras esa expresion no basta: hay que procesar cada palabra. En la practica los equipos lo resuelven con una funcion almacenada que recorre la cadena y pone en mayuscula la letra tras cada espacio, o llevan la logica a la capa de aplicacion. ClickHouse tampoco tiene
INITCAP, pero ofreceupperUTF8,lowerUTF8ysubstring, con los que se construye la misma emulacion.En resumen: en PostgreSQL
INITCAPes estupendo para normalizar rapido cadenas ASCII simples, pero no le confies apellidos con apostrofos, guiones o mayusculas interiores; en MySQL y ClickHouse logras el mismo efecto a mano conUPPER+LOWER+SUBSTRING.