Trocando o Collate de um Banco de Dados SQL Server
Introdução
Este artigo tem sua origem em uma pergunta postada no Fórum TechNet Brasil do SQL Server - Troca de Collate de um determinado banco de dados e também influenciada pela enorme necessidade de esclarecimentos em posts dos Fórum TechNet Internacional. Este é um problema muito comum sobre à manipulação de dados através do T-SQL e serve para outros produtos que utilizam os recursos do SQL Server, tais como: SharePoint e System Center.
Esta é uma das possíveis soluções relacionadas para este problema, se você conhece outras opções em T-SQL que atendam à necessidade do problema proposto, fique à vontade para acrescentar seu conteúdo neste artigo.
Problema
Durante minha leitura nos Threads do Fórum de SQL, encontrei à seguinte pergunta que estava em discussão até então.
A pergunta era: "Gostaria de alterar a collate de um determinado banco de dados, porém gostaria de saber se para alterar um collate de um banco preciso também aplicar nas colunas das tabelas existente? Tem algum procedimento que faça em todas às colunas ou tenho que aplicar manualmente coluna à coluna ?"
É preciso estar claro que o inquiridor da pergunta, já havia alterado o Collation do banco de dados para SQL_Latin1_General_CP1_CI_AI, e passou a receber diversos erros em consultas, principalmente onde os campos do tipo varchar faziam parte das condições em um comando JOIN.
Quando tentou alterar o Collation dos campos em uma tabela, surgiu o seguinte erro:
ALTER TABLE BibliografiaTipos ALTER COLUMN Descricao varchar(50) COLLATE SQL_Latin1_General_CP1_CI_AI
--RESULTADO
Msg 4902, Level 16, State 1, Line 4
Cannot find the object "BibliografiaTipos" because it does not exist or you do not have permissions.
Um segundo erro surgiu, quando o inquiridor tentou alterar tabelas com campo texto que possuíam relacionamento entre tabelas do Banco de Dados, além de campos texto com chave prímária.
Msg 5074, Level 16, State 1, Line 5
The object ‘FK_FrequenciasNova_Alunos’ is dependent on column ‘Aluno_RA’.
Msg 4922, Level 16, State 9, Line 5
ALTER TABLE ALTER COLUMN Aluno_RA failed because one or more objects access this column.
Ter campos texto como chave primária fez toda diferença para a solução do problema. Vamos ver como foi executada esta alteração.
Causas
Quando alteramos o Collation de um banco de dados, todos os campos dos tipos: char, nchar, varchar, nvarchar permanecem no Collation em que foram criados. É necessário analisar com cuidado qual é a melhor solução para reduzir ao máximo o impacto nos sistemas cliente e nas consultas que os usuários já realizavam.
Para ajudar à compreender
Isto porque, poderá ocorrer alterações no resultado de suas consultas. Em um dia, o seu relatório traz todas às informações e logo após a troca do Collation pode não retornar mais nada.
Alterar o Collation apenas em uma instrução ( SELECT, INSERT, UPDATE ou DELETE ) também não é recomendado, porque existe à possibilidade de gerar lentidão durante à conversão.
Então, de fato, a melhor solução no contexto deste post do Fórum é alterar o Collation de cada campo nas tabelas existentes.
Apenas esclarecendo, novos campos do tipo texto, como citados acima, criados após a mudança do Collation no Banco de Dados passarão à adotar o mesmo Collation indicado na configuração do Banco.
Etapas de Diagnóstico
Depois de diagnosticarmos à causa do problema, vamos para à sua resolução. Podem existir outras soluções como alternativa, mas esta indicada no final do artigo compreende exatamente à pergunta proposta no Fórum, da forma mais simples e prática possível.
Construíndo o Cenário do Problema
Para que possamos simular com precisão o problema e propor à sua solução, vamos construir uma tabela semelhante à situação indicada no Thread do Fórum (Figura 1):
SELECT name, collation_name FROM sys.databases WHERE name = 'WI_Infra'
GO
CREATE TABLE BibliografiaTipos (
ID int PRIMARY KEY NOT NULL,
NM_USER varchar(100) COLLATE SQL_Latin1_General_CP1_CI_AI NOT NULL,
Descricao varchar(250) NOT NULL
)
GO
sp_help BibliografiaTipos
GO
Figura 1 - Criando a tabela para demonstração da solução e indicando os Collations diferentes entre Banco e Tabela
Verificando o Cenário do Problema
Para que possamos entender o porque houve erro ao alterar o Collation da tabela é importante verificar qual é o "schema" na qual os campos da tabela pertencem e incluir na alteração da coluna à opção do campo em receber valores nulos ou não:
sp_help BibliografiaTipos
GO
ALTER TABLE BibliografiaTipos ALTER COLUMN Descricao varchar(250) COLLATE SQL_Latin1_General_CP1_CI_AI NULL
GO
Ainda assim, temos o último Problema do Inquiridor: campos texto com chave e/ou índice.
Solução
Parte da solução já foi realizada, orientando o inquiridor a corrigir o ALTER TABLE para alteração do Collation da coluna. É importante estar claro que a indicação das pequenas correções no cenário já atenderiam boa parte das tabelas no banco de dados, por não possuírem campos texto como chave primária ou estrangeira.
Para estruturar à segunda parte da solução do problema, de forma simples e eficiente, o inquiridor foi orientado à seguir alguns passos:
- Criar os scripts de todas às tabelas onde o campo texto é a chave primária
- Incluir no nome das tabelas deste script o termo "_NOVO"
- Efetuar um backup FULL do Banco de Dados
- Executar o script de carga de dados com INSERT / SELECT para tabelas onde a chave primária é um campo texto
- Executar o script de carga de dados com INSERT / SELECT com para tabelas onde a chave estrangeira é um campo texto e a chave primária é um identity
Vamos executar à carga de dados da tabela antiga para a nova, onde a chave primária é um campo texto
INSERT INTO FrequenciasNova_Alunos_NOVO
(ID_ALUNO, NM_ALUNO)
SELECT
ID_ALUNO,
NM_ALUNO COLLATE SQL_Latin1_General_CP1_CI_AI
FROM FrequenciasNova_Alunos;
Para executar à carga de dados da tabela antiga para a nova, onde a chave estrangeira é um campo texto e a chave primária é um identity é necessário declarar todos os campos da tabela. Incluindo a configuração "SET IDENTITY_INSERT" no início e no fim da instrução desabilitando e habilitando novamente a carga de dados em campos Identity.
SET IDENTITY_INSERT FrequenciasNova_Alunos_NOVO ON
INSERT INTO FrequenciasNova_Alunos_NOVO
(ID_ALUNO, NM_ALUNO)
SELECT
ID_ALUNO,
NM_ALUNO COLLATE SQL_Latin1_General_CP1_CI_AI
FROM FrequenciasNova_Alunos;
SET IDENTITY_INSERT FrequenciasNova_Alunos_NOVO OFF
Conclusão, para executar a troca de um Collation de um banco de dados é necessário à realização de uma análise prévia para identificar quais tabelas serão afetadas e como esta alteração deve ser efetuada. Em alguns casos, é necessário executar à recriação da tabela com outro nome, seguida da importação dos dados da tabela com o Collation anterior.
Veja Também
Leia alguns artigos relacionados ao assunto:
Para fortalecer o seu conhecimento sobre COLLATE e IDENTITY recomendo à leitura dos artigos:
- IDENTITY (pt-BR)
- Solucionando Problemas: Armazenamento/Consulta que contenham caracteres especiais no SQL Server (pt-BR)
- SQL Server Installation and database creation with Visual Studio setup (en-US)
Biblioteca TechNet
Leia alguns tópicos relacionados ao assunto:
- Collation and Unicode Support
- ALTER TABLE (Transact-SQL)
- COLLATE (Transact-SQL)
- Collation Precedence (Transact-SQL)
- Collation and Unicode Support
- Altering a column definition
- SET IDENTITY_INSERT (Transact-SQL)
Referências
Leia alguns posts relacionados ao assunto:
- Blog MCDBA - Alterando o Collate Default do Servidor
- Blog TechNet System Center 2012 - Clarification on SQL Server Collation Requirements for System Center 2012
Créditos
Este artigo foi escrito inspirado nos artigos:
- Modelo para Converter um Thread do Fórum dentro de um Novo Artigo Wiki
- Edição Técnica
- Boas Práticas para Referências e Citações
- Wiki: Diretrizes de Experiência do Usuário
Meu agradecimento especial à Richard Mueller por me orientar na premiação do TechNet Guru de dezembro de 2013, explicando como organizar meu conteúdo em seções de forma adequada.
Outros Idiomas
Este artigo também pode ser encontrado em outros idiomas: