sqlpostgresqlinitcapstring-functions

INITCAP en PostgreSQL: poner en mayuscula cada palabra

Como INITCAP pone en mayuscula la primera letra de cada palabra en PostgreSQL, donde falla con apostrofos y guiones, y como imitarlo en MySQL.

2 min de lecturaReferencesql · postgresql · initcap · string-functions · mysql

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');        -- John Doe
SELECT initcap('HELLO world');     -- Hello World
SELECT initcap('order #42 paid');  -- 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.

-- 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 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');        -- O'Brien   (B capitalized after the quote)
SELECT initcap('jean-luc PICARD'); -- Jean-Luc Picard
SELECT initcap('mcdonald');        -- Mcdonald  (not 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:

-- 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 con UPPER, LOWER y 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;

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.

Practica con ejercicios reales

Resuelve ejercicios en el entrenador de SQL con corrección instantánea y pistas.

Abrir el entrenador