top of page

Migração de dados com troca de FK

Esta semana concluí uma migração de dados de uma base para outra. Seria um trabalho simples de INSERT/SELECT, não fosse um fato bem "insignificante": na migração, os valores das chaves primárias das tabelas de origem teriam um valor diferente na tabela de destino. Com isso, todas as chaves estrangeiras referenciadas teriam que ser atualizadas para o novo valor.

Depois de um levantamento completo da estrutura dos BDs envolvidos, a definição da ordem de execução das tabelas, atualizando sempre as tabelas PAI de relacionamentos antes das respectivas tabelas FILHO do relacionamento, e o mapeamento de/para das colunas, resolvi o problema da conversão das FKs de um jeito simples.

Uma informação importante: todas as tabelas dos BDs origem e destino foram criadas com IDENTITY.

Segue o passo a passo da migração.

Script 1

  • Criar uma coluna para cada PK e FK na tabela de destino. Para facilitar, o nome da nova coluna era formado pelo nome da coluna original acrescido do sufixo "_Origem". Por exemplo: IdtCliente_Origem.

  • Criar um índice para cada coluna PK e FK na tabela de destino.

Script 2

  • Execução de INSERT/SELECT para cada tabela envolvida na migração, respeitando a ordem de prioridade de tabelas PAI de relacionamentos antes das tabelas FILHA dos relacionamentos.

  • No comando INSERT/SELECT, eu preenchi as colunas "*_Origem" com o respectivo valor da tabela de origem. Por exemplo:

  • INSERT Cliente (Nome, CPF, DtNascimento, IdCliente_Origem) SELECT O.NomeCliente, O.CPF, O.DtNascimento, O.IdCliente FROM BD_Origem.dbo.Clientes

  • A chave primária da tabela Clientes (IdCliente) foi preenchida automaticamente pelo SQL Server, pois trata-se de uma coluna IDENTITY.

  • Na migração de dados de uma tabela filha da tabela Clientes, eu usei um JOIN para pegar o novo valor de identificação do cliente.

  • INSERT Endereco (IdCliente, Endereco, Bairro, Cidade, UF, CEP, IdEndereco_Origem, IdCliente_Origem) SELECT C.IdCliente, E.Endereco, E.Bairro, E.Cidade, E.UF, E.CEP, E.IdEndereco, E.IdCliente FROM BD_Origem.dbo.Endereco AS E INNER JOIN BD_Novo.dbo.Cliente AS C ON E.IdCliente = C.IdCliente_Origem

  • Este JOIN, ligando o código do cliente da tabela Endereço com o código do cliente na tabela Cliente no BD novo, mas usando o código do cliente na tabela origem, é que permite localizar o novo código do cliente, criado no BD novo, mantendo a integridade da informação.

Script 3

  • Com a migração de dados concluída, executei um script que grava os valores das colunas PK e FK do BD Origem e do BD Destino, guardando o De/Para gerado na migração. Neste caso, montei uma tabela simples, sem me preocupar muito com normalização. Afinal, essa tabela é apenas para mim. Este é o script da tabela:

  • CREATE TABLE [Oxxy].[TB_Migracao]( [IdMigracao] [int] IDENTITY(1,1) NOT NULL, [NmTabela] [varchar](128) NULL, [NmPK] [varchar](128) NULL, [IdPkTabela] [int] NULL, [IdPkTabela_Origem] [int] NULL, [NmColuna_Origem_01] [varchar](128) NULL, [VlrColuna_Origem_01] [int] NULL, [VlrColuna_Destino_01] [int] NULL, [NmColuna_Origem_02] [varchar](128) NULL, [VlrColuna_Origem_02] [int] NULL, [VlrColuna_Destino_02] [int] NULL, [NmColuna_Origem_03] [varchar](128) NULL, [VlrColuna_Origem_03] [int] NULL, [VlrColuna_Destino_03] [int] NULL, [NmColuna_Origem_04] [varchar](128) NULL, [VlrColuna_Origem_04] [int] NULL, [VlrColuna_Destino_04] [int] NULL, [NmColuna_Origem_05] [varchar](128) NULL, [VlrColuna_Origem_05] [int] NULL, [VlrColuna_Destino_05] [int] NULL, [NmColuna_Origem_06] [varchar](128) NULL, [VlrColuna_Origem_06] [int] NULL, [VlrColuna_Destino_06] [int] NULL ) ON [PRIMARY] GO

  • Criei até 6 colunas origem/destino, porque foi o máximo que precisei tratar.

  • A cópia das chaves para a tabela TB_Migracao seguiu este formato:

  • INSERT TB_Migracao (NmTabela, NmPK, IdPkTabela, IdPkTabela_Origem) SELECT 'Cliente' AS NmTabela, 'IdCliente' AS NmPK, IdCliente AS IdPkTabela, IdCliente_Origem AS IdPkTabela_Origem FROM Cliente WHERE IdCliente_Origem IS NOT NULL

INSERT TB_Migracao (NmTabela, NmPK, IdPkTabela, IdPkTabela_Origem, NmColuna_Origem_01, VlrColuna_Origem_01, VlrColuna_Destino_01) SELECT 'Endereco' AS NmTabela, 'IdEndereco' AS NmPK, IdEndereco AS IdPkTabela, IdEndereco_Origem AS IdPkTabela_Origem_,

'IdCliente' AS NmColuna_Origem_01, IdCliente_Origem AS VlrColuna_Origem_01, IdCliente AS VlrColuna_Destino_01 FROM Endereco WHERE IdEndereco_Origem IS NOT NULL OR IdCliente_Origem IS NOT NULL​

Script 4

  • Exclusão de todos os índices das colunas _Origem.

  • Exclusão de todas as colunas _Origem.

O Bote salva-vidas

A tabela TB_Migracao acabou me salvando. Dentre as colunas migradas, teve uma que o desenvolvedor me informou errado. Foi necessário atualizar os dados. Como as colunas _Origem foram excluídas da tabela, se eu não tivesse a TB_Migracao para identificar os registros e valores tratados, seria muito mais complicado corrigir o valor desta FK.

Para atualizar a tabela, eu:

  • Copiei os registros com problema para uma tabela temporária.

  • Excluí os registros criados na primeira importação, ligando a tabela com problema à TB_Migracao.

  • Atualizei a tabela TB_Migracao, marcando os registros que foram excluídos.

  • Extrai, dos scripts acima, os comandos que envolviam a tabela com problema.

  • Fiz as correções necessárias.

  • Executei novamente.

Sucesso!

Concluindo, fica aqui minha sugestão para vocês. Numa migração de dados entre tabelas ou Bancos de Dados, onde os valores de PK e FK são modificados, guarde o de/para numa tabela separada. Você nunca sabe quando vai precisar.

Posts Em Destaque
Posts Recentes
Arquivo
Procurar por tags
bottom of page