Como Deixar Apenas a Primeira Letra de uma Coluna em Maiúscula no SQL Server
Um problema comum ao lidar com dados digitados de forma inconsistente (tudo em maiúsculas, tudo em minúsculas, ou uma mistura dos dois) é padronizar o texto deixando apenas a primeira letra maiúscula e o restante minúsculo. O SQL Server não tem uma função nativa pronta para isso (diferente de outros bancos, como o INITCAP do Oracle), mas é possível resolver com uma function personalizada.
Vale notar que existem dois resultados diferentes que costumam ser confundidos sob o mesmo nome:
-
Primeira letra da string inteira em maiúscula: por exemplo,
"joão da silva"vira"João da silva". -
Primeira letra de cada palavra em maiúscula (também chamado de Title Case ou Proper Case): por exemplo,
"joão da silva"vira"João Da Silva".
Veja abaixo como resolver os dois casos.
Apenas a primeira letra da string
Se o que você precisa é só a primeira letra maiúscula, sem mexer nas demais palavras, uma expressão simples já resolve, sem precisar de function:
SELECT UPPER(LEFT(Nome, 1)) + LOWER(SUBSTRING(Nome, 2, LEN(Nome))) AS NomeFormatado
FROM Clientes;
Se preferir encapsular isso em uma function reutilizável:
CREATE FUNCTION fn_PrimeiraLetraMaiuscula (@Texto VARCHAR(100))
RETURNS VARCHAR(100)
AS
BEGIN
RETURN UPPER(LEFT(@Texto, 1)) + LOWER(SUBSTRING(@Texto, 2, LEN(@Texto)));
END;
Primeira letra de cada palavra em maiúscula (Title Case)
Quando o objetivo é colocar a primeira letra de cada palavra em maiúscula, como em nomes compostos ou endereços, é preciso percorrer o texto procurando os espaços. A function abaixo faz exatamente isso:
CREATE FUNCTION fn_RightCase (@Nome VARCHAR(100))
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE @StrTemp VARCHAR(100);
DECLARE @i INT;
SET @StrTemp = LOWER(@Nome);
SET @StrTemp = UPPER(LEFT(@StrTemp, 1)) + SUBSTRING(@StrTemp, 2, LEN(@StrTemp));
WHILE CHARINDEX(' ', @StrTemp, 1) > 0
BEGIN
SET @i = CHARINDEX(' ', @StrTemp, 1);
SET @StrTemp = LEFT(@StrTemp, @i - 1) + '|' +
UPPER(SUBSTRING(@StrTemp, @i + 1, 1)) +
SUBSTRING(@StrTemp, @i + 2, LEN(@StrTemp));
END;
SET @StrTemp = REPLACE(@StrTemp, '|', ' ');
RETURN @StrTemp;
END;
Uso:
SELECT dbo.fn_RightCase('JOÃO DA SILVA');
-- Resultado: João Da Silva
A lógica é: primeiro deixa tudo minúsculo, depois coloca a primeira letra da string em maiúscula, e então percorre o texto trocando temporariamente cada espaço por | enquanto coloca em maiúscula a letra seguinte, até não sobrar mais nenhum espaço. No final, os | voltam a ser espaços.
Uma alternativa sem loop (SQL Server 2022 em diante)
A partir do SQL Server 2022, é possível montar o mesmo resultado sem WHILE, combinando STRING_SPLIT (com a opção de retornar a posição de cada palavra) e STRING_AGG:
CREATE FUNCTION fn_TitleCase (@Texto VARCHAR(100))
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE @Resultado VARCHAR(100);
SELECT @Resultado = STRING_AGG(
UPPER(LEFT(value, 1)) + LOWER(SUBSTRING(value, 2, LEN(value))), ' '
) WITHIN GROUP (ORDER BY ordinal)
FROM STRING_SPLIT(@Texto, ' ', 1);
RETURN @Resultado;
END;
Atenção: o terceiro parâmetro de STRING_SPLIT (que habilita a coluna ordinal, usada para manter a ordem original das palavras) só existe a partir do SQL Server 2022. Em versões anteriores, STRING_SPLIT não garante a ordem das palavras retornadas, então usar essa abordagem em versões mais antigas pode embaralhar a ordem do texto original. Para SQL Server 2019 ou anterior, prefira a function com WHILE mostrada acima.
Um ponto de atenção sobre performance
Functions escalares como fn_RightCase, que usam WHILE e são chamadas dentro de um SELECT, tendem a ser executadas linha a linha (o famoso RBAR, row-by-agonizing-row), o que pode ficar lento em tabelas grandes. Desde o SQL Server 2019 existe um recurso chamado Scalar UDF Inlining, que reescreve automaticamente algumas functions escalares simples como se fossem parte da própria consulta, melhorando bastante a performance. Porém, functions com WHILE, como a fn_RightCase, não se qualificam para essa otimização automática, então o custo linha a linha continua existindo nelas.
Se você for aplicar essa formatação em tabelas muito grandes com frequência, vale considerar:
- Rodar a formatação uma única vez, em um
UPDATE, e manter a coluna já formatada, em vez de formatar em tempo de leitura a cada consulta. - Usar a versão sem loop (SQL Server 2022+) quando disponível, por ser mais amigável à otimização do mecanismo de execução.
Conclusão
Para deixar só a primeira letra da string em maiúscula, uma expressão simples com UPPER e LEFT já resolve. Para colocar a primeira letra de cada palavra em maiúscula (Title Case), a function com WHILE continua sendo a forma mais compatível entre versões, e no SQL Server 2022 em diante já é possível fazer o mesmo sem loop, combinando STRING_SPLIT e STRING_AGG.