sqlpostgresqlinitcapstring-functions

INITCAP no PostgreSQL: primeira letra de cada palavra em maiuscula

Como o INITCAP deixa a primeira letra de cada palavra em maiuscula no PostgreSQL, onde ele falha com apostrofos e hifens, e como imita-lo no MySQL.

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

INITCAP e uma funcao do PostgreSQL que coloca em maiuscula a primeira letra de cada palavra e o resto em minuscula. E util para normalizar nomes, cidades e rotulos para um title-case uniforme, mas traz algumas limitacoes pouco obvias que vale conhecer de antemao.

O que o INITCAP faz

INITCAP recebe uma string, divide em palavras e, para cada palavra, eleva a primeira letra a maiuscula enquanto forca todas as demais a minuscula. Uma palavra e qualquer sequencia de caracteres alfanumericos; um limite de palavra e qualquer caractere nao alfanumerico (espaco, ponto, hifen, apostrofo e assim por diante).

SELECT initcap('john DOE');        -- John Doe
SELECT initcap('HELLO world');     -- Hello World
SELECT initcap('order #42 paid');  -- Order #42 Paid

Repare que a caixa interna original nao e preservada. INITCAP sempre normaliza cada palavra para "primeira letra maiuscula, o resto minusculo", entao 'McDONALD' vira 'Mcdonald'.

Normalizar nomes e cidades

O caso classico sao dados que chegaram de um formulario ou de uma importacao com caixa arbitraria e que precisam ser exibidos de forma limpa.

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

Voce tambem pode gravar de volta o valor normalizado, se quiser dados limpos em repouso:

-- One-off cleanup of inconsistent name casing
UPDATE users
SET name = initcap(name)
WHERE name <> initcap(name);

Onde o INITCAP quebra

A grande armadilha e que o INITCAP trata qualquer caractere nao alfanumerico como limite de palavra. Para nomes reais isso costuma estar errado:

  • um apostrofo inicia uma "nova palavra", entao a letra seguinte recebe maiuscula;
  • hifens e apostrofos dentro de um nome sao todos tratados como separadores;
  • maiusculas internas (como em McDonald) se perdem: caem para 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)

Pegadinha: o INITCAP nao conhece regras culturais como McDonald, van der Berg ou DeShawn. Ele sempre coloca maiuscula depois de um apostrofo ou hifen, e perde as maiusculas internas de uma palavra. Para marcas e sobrenomes com grafia especial, nao confie no INITCAP — guarde a forma canonica separadamente.

A segunda sutileza e o locale e o Unicode. O PostgreSQL muda a caixa conforme o locale do banco, e para alguns pares (o i/I turco, por exemplo) o resultado pode diferir do esperado. Nomes ASCII sao previsiveis, mas com dados multilingues verifique o comportamento no seu proprio locale.

Se o INITCAP so estraga algumas linhas, nao grave o resultado na tabela inteira: selecione as linhas problematicas e corrija o resto no lugar:

-- 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 no MySQL: emulacao

O MySQL nao tem INITCAP. Para uma unica palavra e facil montar com UPPER, LOWER e 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 strings de varias palavras essa expressao nao basta: e preciso processar cada palavra. Na pratica os times resolvem com uma funcao armazenada que percorre a string e coloca em maiuscula a letra depois de cada espaco, ou empurram a logica para a camada de aplicacao. O ClickHouse tambem nao tem INITCAP, mas oferece upperUTF8, lowerUTF8 e substring, com os quais se constroi a mesma emulacao.

Resumo: no PostgreSQL o INITCAP e otimo para normalizar rapido strings ASCII simples, mas nao confie nele para sobrenomes com apostrofos, hifens ou maiusculas internas; no MySQL e no ClickHouse voce obtem o mesmo efeito na mao com UPPER + LOWER + SUBSTRING.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador