Quero capitalizar apenas a primeira letra de cada palavra de cada frase em uma coluna SQL.
Por exemplo, se a frase for:
'Eu gosto de filmes'
então eu preciso da saída:
'Eu gosto de filmes'
Consulta:
declare @a varchar(15)
set @a = 'qWeRtY kEyBoArD'
select @a as [Normal text],
upper(@a) as [Uppercase text],
lower(@a) as [Lowercase text],
upper(left(@a,1)) + lower(substring(@a,2,len(@a))) as [Capitalize first letter only]
Aqui eu coloquei a primeira letra superior, inferior e maiúscula apenas na minha coluna (aqui coloquei apenas uma palavra aleatória).
Aqui estão meus resultados:
Existe alguma possibilidade de fazer isso?
Alguma possibilidade de obter resultados sem usar a função definida pelo usuário?
Eu preciso da saídaQwerty Keyboard
Isso primeiro converte a string em XML substituindo todos os espaços pela tag vazia
<X/>
. Em seguida, ele fragmenta o XML para obter uma palavra por linha usandonodes()
. Para obter as linhas de volta a um valor, ele usa ofor xml path
truque.No SQL Server 2016 você pode fazer isso com R, por exemplo
Se você deve ou não é uma questão diferente :)
Talvez eu esteja sendo bobo, mas verificando a consulta abaixo que escrevi em relação a alguns dos fornecidos, isso parece ser um pouco mais eficiente (dependendo da indexação).
O código é um pouco estúpido, mas não existe um ditado que se parece estúpido, mas funciona, então não é estúpido.
Outra opção é lidar com isso via SQLCLR. Existe até um método já disponível no .NET que faz isso: TextInfo.ToTitleCase (em
System.Globalization
). Este método colocará em maiúsculas a primeira letra de cada palavra e em minúsculas as letras restantes. Ao contrário das outras propostas aqui, também pula palavras que estão todas em maiúsculas, assumindo que sejam siglas. Obviamente, se esse comportamento for desejado, seria bastante fácil atualizar qualquer uma das sugestões do T-SQL para fazer isso também.Um benefício do método .NET é que ele pode usar letras maiúsculas que são caracteres suplementares. Por exemplo: DESERET SMALL LETTER OW tem um mapeamento maiúsculo de DESERET CAPITAL LETTER OW (ambos aparecem como caixas quando coloco aqui) , mas a
UPPER()
função não altera a versão minúscula para maiúscula, mesmo quando o Collation padrão para o banco de dados atual é definido comoLatin1_General_100_CI_AS_SC
. Isso parece consistente com a documentação do MSDN que não listaUPPER
eLOWER
no gráfico de funções que se comportam de maneira diferente ao usar um_SC
Collation: Collation and Unicode Support: Supplementary Characters .Retorna (ampliado para que você possa realmente ver o caractere suplementar):
Você pode ver a lista completa (e atual) de caracteres que são minúsculos e mudar para maiúsculas usando o seguinte recurso de pesquisa em Unicode.org (você pode ver os caracteres suplementares rolando para baixo até chegar ao "DESERET" seção, ou apenas clique Control-Fe procure por essa palavra):
http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AChanges_When_Titlecased%3DYes%3A%5D
Embora, para ser honesto, isso não seja um grande benefício, pois é duvidoso que alguém esteja realmente usando qualquer um dos personagens suplementares que podem ser incluídos no título. De qualquer forma, aqui está o código SQLCLR:
Aqui está a sugestão de @MikaelEriksson - ligeiramente modificada para lidar com
NVARCHAR
dados, bem como pular palavras que são todas em maiúsculas (para corresponder mais de perto ao comportamento do método .NET) - junto com um teste dessa implementação T-SQL e de a implementação SQLCLR:Outra diferença de comportamento é que essa implementação T-SQL específica se divide apenas em espaços, enquanto o
ToTitleCase()
método considera a maioria das não letras como separadores de palavras (daí a diferença no tratamento da parte "um&DOIS").Ambas as implementações tratam de sequências de combinação corretamente. Cada uma das letras acentuadas em "üvÜlA" é composta por uma letra base e uma combinação de trema / trema (os dois pontos acima de cada letra), e são convertidas corretamente para o outro caso em ambos os testes.
Finalmente, uma desvantagem inesperada para a versão SQLCLR é que, ao fazer vários testes, encontrei um bug no código .NET relacionado ao manuseio das letras circuladas (que agora foi relatado no Microsoft Connect — ATUALIZAÇÃO: o Connect foi movido para
/dev/null
-- literalmente -- então talvez eu precise reenviar isso se o problema ainda existir). A biblioteca .NET trata as letras circuladas como separadores de palavras, razão pela qual não transforma o "ⓐDD" em "Ⓐdd" como deveria.Para sua informação
Uma função SQLCLR pré-configurada que encapsula o
TextInfo.ToTitleCase
método mencionado acima agora está disponível na versão gratuita do SQL# (que eu escrevi) como String_ToTitleCase e String_ToTitleCase4k .?
Como alternativa à resposta de Mikael Eriksson , você pode considerar o uso do tratamento T-SQL proprietário da configuração de variáveis em instruções de seleção de várias linhas.
No SQL Server, quando uma variável está sendo definida como parte de uma instrução SELECT, cada linha executará uma iteração da lógica definida.
As pessoas costumam usar esse método para concatenar strings, embora não seja compatível e haja alguns problemas oficialmente documentados com ele . O problema oficial está relacionado a características particulares de ORDER BY, e não precisamos disso aqui, então talvez seja uma opção segura.
Aqui, iteramos as 26 letras do alfabeto e as substituímos por uma versão em maiúsculas se forem precedidas por um espaço. (Preparamos a string inicialmente colocando a primeira letra em maiúscula e deixando o resto em minúscula, como você fez na sua pergunta.)
O SQL é um pouco complexo porque requer o uso de uma Tabela Tally - uma tabela de números - para gerar as 26 iterações de substituição que está fazendo. Você pode criar uma função definida pelo usuário (TVF) com valor de tabela em linha para produzir essa tabela de números ou pode até usar uma tabela física.
Uma desvantagem dessa opção é que ela não pode fazer parte de um TVF embutido, pois precisa envolver a configuração de uma variável. Portanto, se você quiser aplicar esse método a uma coluna de sua saída, precisará envolvê-lo em um TVF de várias instruções ou em uma função escalar definida pelo usuário.
No entanto, seu plano de consulta é muito mais simples e provavelmente é significativamente mais rápido que o método XML. Você pode argumentar que é mais fácil de entender também (especialmente se você tiver sua própria tabela de contagem).
(Eu testei isso usando uma string muito maior e foi cerca de 6ms vs 14ms para a solução XML.)
Há uma série de limitações adicionais com esta solução. Conforme escrito, ele assume uma ordenação que não diferencia maiúsculas de minúsculas, embora você possa eliminar esse problema especificando uma ordenação ou executando LCASE no termo de pesquisa, ao custo de algum desempenho. Ele também aborda apenas letras ASCII padrão e depende de seu posicionamento no conjunto de caracteres , portanto, não faria nada com ñ.
Supondo que você esteja apenas procurando capitalizar palavras após um espaço, aqui está outra maneira de fazer isso.
Pode não ser à prova de balas, mas espero que seja uma contribuição útil para este tópico.
Abaixo está o procedimento que usei em um banco de dados Firebird para fazer isso. Provavelmente pode ser limpo muito, mas fez o trabalho para mim.
CTEs recursivos são muito bons para esse tipo de coisa.
Provavelmente não é particularmente eficiente para grandes operações, mas permite esse tipo de operação em uma instrução de seleção SQL pura:
Resultado:
Eu gosto desta versão. É simples, e pode ser usado para criar uma função, basta ter a versão correta do SQL Server: