Solucionando Problemas: Armazenamento/Consulta que contenham caracteres especiais no SQL Server (pt-BR)
Introdução
Nos campos de texto (varchar, nvarchar, text, etc...) os DBA's costumam ter vários problemas ocasionados por informações incorretas e/ou repetidas inseridas por usuários que se diferenciam apenas por acentos ou por cedilhas. Ou seja, um usuário pode cadastrar o nome de um cliente como "JOAO DA SILVA" e outro "JOÃO DA SILVA" e o SQL Server, normalmente, considerará os dois registros diferentes. Isso gera um erro em consultas e muitas vezes em Chaves (primária / unique).
Isso ocorre devido a Collation selecionada para o campo está sensível a acentos. Para entender melhor essa resolução dos problemas vamos entender um pouco mais sobre as Collations do SQL Server.
Resolvendo esse problema
Collation
Definindo de uma forma bem básica, é um conjunto de regras sobre um determinado conjunto de caracteres baseado principalmente em idiomas. Para você entender melhor pense na língua portuguesa e suas regras e agora imagine regras na escrita alemã ,ou na japonesa, ou ainda na árabe. São totalmente diferentes e precisam ser tratadas diferentes no armazenamento e na busca. Para que isso seja possível existem os Collations.
Mas não posso ser tão simplista e deixar de comentar que as Collations também podem controlar detalhes da forma de pesquisar, como: sensibilidade à maiúsculas ou não, sensibilidade à acentos ou não, etc).
Para entender melhor como escolher um collation para a coluna do seu banco de dados, vamos analisar como é a nomeclatura dos Collations. Por exemplo, um dos Collations mais utilizados no Brasil: SQL_Latin1_General_CP1_CI_AI.
Para maior didática, vou dividir o nome da Collation da seguinte forma:
SQL_Latin1_General_ -> É o nome
CP1_ ->Significa que vai usar Unicode para codificação e ordenamento (não vou falar muito, pois não será o foco hoje)
CI_ -> Case Insensitive, ou seja, não sensível a maiúsculas e minúsculas. Se aqui tivesse CS, então seria Case Sensitive, ou seja, sensível a maiúsculas e minúsculas
AI_ ->Accent Insensitive, ou seja, não sensível à acentos. Se aqui tivesse AS, então seria Accent Sensitive, ou seja, sensível a acentos
E ainda existem outras partes da nomeclatura, mas para as língua latinas não vão importar; portanto, não vou me alongar nesse assunto.
É possível definir a configuração de Collation em quatro níveis distintos no SQL Server:
- Instância: Configuração aplicada a todos os bancos criados por padrão. Definida na instalação do SQL Server ou nas propriedades do servidor.
- Banco de Dados: Configuração aplicada ao banco de dados, ignorando a configuração da instância. Definida na criação ou alteração da base.
- Coluna: Configuração aplicada a uma coluna específica, desconsiderando o Collation definido para o banco de dados. Definida na criação a tabela ou alteração do campo da tabela.
- Consulta: Configuração válida somente durante a execução de comandos SELECT, através da cláusula ORDER BY. Esta opção em especial é interessante por não realizar nenhuma alteração nos dados já armazenados no SQL Server; a mudança é valida somente para os dados resgatados durante a consulta.
Para examinar outras collations você pode executar a seguinte consulta que vai retornar o nome da Collation e a descrição:
select * from fn_helpcollations()
**
Na prática**
Vamos utilizar o exemplo supracitado: os usuários estavam cadastrando nomes de pessoas e colocavam acento no nome e outros não, gerando duplicidade e inconsistência no banco de dados. Por exemplo, um usuário cadastrava “João da Silva” e outro cadastrava “Joao da Silva”. Estamos falando da mesma pessoa; porém dois registros foram inseridos porque a Collation utilizada era a SQL_Latin1_General_CP1_CI_AS, que é sensível à acentos, sendo assim, considera os dois nomes diferentes.
A solução é alterar a Collation do campo em questão para usar a SQL_Latin1_General_CP1_CI_AI (que não é sensível ao acento). Usei a seguinte query:
ALTER TABLE [dbo].[tb_cliente]
ALTER COLUMN [nm_cliente] varchar(50) collate SQL_Latin1_General_CP1_CI_AI not nullPronto, agora ninguém mais conseguirá cadastrar “Joao da Silva” e depois “João da Silva”, pois isso ocasionará um erro devido a esse campo ser Unique. E ao consultar, tanto faz escrever “Joao” como “João”, o SQL Server retornará o usuário em questão.
Outra Collation que também pode resolver seu problema é a sql_latin1_general_cp1251_cs_as. Com essa Collation os acentos são literalmente retirados. Como podemos ver nos dois exemplos abaixo:
Exemplo 1:
Declare @cExpressao varchar(30)
Set @cExpressao = 'aeiouáéíóúàèìòòâêîôûãõäëïöüç'
Select @cExpressao collate sql_latin1_general_cp1251_cs_as
Exemplo 2:
create table teste (nome varchar(30) collate sql_latin1_general_cp1251_cs_as null)
insert into teste values ('aeiouáéíóúàèìòòâêîôûãõäëïöüç')
select * from teste
Cuidados
Só lembrando dos cuidados que se deve ter ao modificar um collate:
- verificar se o campo participa de algum índice (clustered ou nonclustered)
- verificar se a modificação não vai gerar conflito de chave primária ou estrangeira e nestes casos, verificar qual o registro correto e qual pode ser excluído
Conclusão
O artigo mostra que é razoavelmente simples resolver problemas de inserção e consulta de dados errados por causa de acentos e outros caracteres. Tomando os devidos cuidados é uma boa saída para manter a consistência dos dados.
Este artigo foi originalmente escrito por:
Fredy Esmeraldo
Microsoft MCP,MCTS, MCITP Database Administrator 2008
blog: http://fredyesmeraldo.wordpress.com
twitter: @fredyesmeraldo