Estou tentando escrever uma consulta que substitui os caracteres especiais por espaço. O código abaixo ajuda a identificar as linhas. (caracteres alfanuméricos, vírgula e espaço são válidos):
SELECT columnA
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'
Como posso integrar a função replace na instrução select para que todos os caracteres que não sejam alfanuméricos, vírgula e espaço no conjunto de resultados sejam substituídos por ' ' (espaço). Este não vai funcionar:
SELECT replace(columnA,'%[^a-Z0-9, ]%',' ')
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'
Se você tiver a garantia de usar apenas as 26 letras do alfabeto inglês dos EUA (versões maiúsculas e minúsculas), com certeza, você pode usar
LIKE
e/ouPATINDEX
com a notação de intervalo simples de[a-z]
(você não usaria precisa usar um "Z" maiúsculo ao usar um agrupamento que não diferencia maiúsculas de minúsculas).Mas, se você pode obter caracteres não encontrados no alfabeto en-US, mas disponíveis em várias páginas de código / agrupamentos para
VARCHAR
dados (por exemploÞ
, maiúsculas latinas "Thorn" =SELECT CHAR(0xDE)
), talvez seja necessário incluí-los na classe de caracteres:[a-z0-9, Þ]
. Claro, o que esses caracteres extras seriam é por página de código.Além disso, esteja ciente de que tanto o tipo de agrupamento (SQL Server vs Windows) quanto as configurações de sensibilidade (maiúsculas, acento, etc. sensível vs insensível) afetarão quais caracteres são incluídos em um intervalo específico. Por exemplo, os agrupamentos do SQL Server classificam letras maiúsculas e minúsculas na ordem oposta aos agrupamentos do Windows. Ou seja, assumindo um Collation que diferencia maiúsculas de minúsculas para ambos os tipos de Collations, um fará
AaBb...
e o outro faráaAbB...
. O efeito será quea
estará dentro do alcance deA-Z
para um deles, mas não para o outro. E o intervalo dea-Z
não corresponderá a nenhum caractere em um Collation binário (um que termine em_BIN
ou_BIN2
, mas não use_BIN
), dado que o valor deA
é 65 ea
é 97, portanto, é um intervalo inválido de 97 a 65 ;-). Existem muitas variações para dar exemplos aqui, então tentarei postar uma explicação detalhada no meu blog em breve (e atualizarei isso com o link para ele). No entanto, se você for rigoroso em aceitar apenas caracteres do inglês americano (mesmo que receba letras válidas de outros idiomas), sua melhor opção provavelmente será usar o seguinte padrão e agrupamento:Agora, se você estiver dando suporte
NVARCHAR
a dados e puder obter caracteres de "palavra" de vários idiomas, o T-SQL não será de muita ajuda, pois não há uma maneira real de diferenciar essas coisas. Nesse caso, você deve usar uma Expressão Regular (RegEx) -- especificamente oReplace
método/função -- e elas só estão disponíveis através do SQLCLR. O seguinte mostra um exemplo de substituição de vários caracteres "especiais", mas deixando todos os que são letras válidas em pelo menos um idioma:Devoluções:
A expressão RegEx significa:
\W
= um RegEx "escape" que significa "qualquer caractere que não seja de palavra"\p{Pc}
= uma "categoria" Unicode de "Pontuação, Conector" (isso é necessário para a correspondência apenas porque essa "categoria" é especificamente excluída pelo\W
escape)-[,]
= subtração de classe (isso é necessário para excluir vírgulas da correspondência como "especial", pois elas são incluídas no\W
escape)Você pode fazer uma atualização de uma tabela simplesmente emitindo:
Observe que, para esses exemplos, usei duas funções disponíveis na versão gratuita da biblioteca SQL# de funções SQLCLR, que criei (mas, novamente, elas são gratuitas). Observe também que usei as versões "4k" que são mais rápidas devido ao uso
NVARCHAR(4000)
em vez deNVARCHAR(MAX)
tipos de parâmetro. Se seus dados estiverem usandoNVARCHAR(MAX)
, basta remover o "4k" dos nomes das funções.Veja também:
Eu tenho um post aqui que faz algo semelhante .
Basicamente, estou usando um CTE recursivo para fazer um loop repetidamente substituindo um caractere "ruim" de cada vez. Estou usando STUFF para retirar 1 caractere (embora você possa usá-lo para substituir por um espaço) e PATINDEX para encontrar a localização do caractere que quero remover. Você pode modificá-lo um pouco para fazer o que está procurando. No entanto, cria uma lista "boa", na verdade não atualiza a lista existente.
Você deve poder modificar a parte inferior para fazer uma atualização em vez de apenas uma consulta, mas eu realmente não tentei. Tenho quase certeza que seria algo assim:
No que diz respeito à escalabilidade, retornei ~ 170k linhas limpas em menos de 30 segundos. Novamente, não tenho certeza sobre como fazer uma atualização, mas isso estava no meu laptop, que é bastante lento, com apenas 6 GB de RAM.