|

Como Deixar Apenas a Primeira Letra de uma Coluna em Maiúscula no SQL Server

Compartilhe :

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.

Posts Similares