Neste artigo veremos |
|
Qual a finalidade? |
|
Quais situações utilizam esses recursos? |
Quando se está implantando um novo sistema em um cliente e o mesmo precisa recuperar os dados já cadastrados em seu antigo sistema desenvolvido por terceiros a maior parte das vezes é criar uma aplicação para migração de dados, como fazer isso? |
Resumo do DevMan
Como importar os dados de um banco para outro que possui a estrutura das tabelas totalmente diferente? Como inserir as dependências e manter a integridade dos dados? Uma aplicação em Delphi é a solução para a maioria dos problemas encontrados na hora de se importar os registros contidos em um banco de dados que será substituído. Este artigo traz um exercício prático para exemplificar a solução para situações como esta, a se aplicar independente do sistema gerenciador de banco de dados usado.
Nada é mais importante para o usuário de um sistema do que manter o cadastro de seus clientes e outros dados importantes quando se fala em substituir seu sistema. Passamos por esta situação quando desenvolvemos um sistema para um cliente que já possuía um outro sistema desenvolvido por terceiros. O problema na hora de importar os dados é que, como existem muitas maneiras de se modelar tabelas de um banco de dados, e como cada programador pensa de um jeito diferente, as tabelas do banco origem às vezes são bem diferentes do banco destino. Outra situação parecida é a que programadores mais experientes com certeza já passaram: ter que atualizar seu antigo sistema que armazenava dados em uma base de dados ultrapassada (Paradox por exemplo), para um banco de dados mais moderno. Nesse caso, o programador, com mais experiência do que quando criou o antigo sistema, encontra soluções mais elaboradas para estruturar o seu novo banco. A idéia desse artigo, para desenvolvedores iniciantes que certamente passarão por essa situação, é mostrar como criar uma aplicação em Delphi que irá acessar os dois bancos, percorrer registro por registro e inserir no banco destino fazendo todo controle de condições para manter a integridade dos dados.
Um exemplo de estruturas de tabelas diferentes seria:
- Banco 1: Contém uma tabela para armazenar clientes, outra para fornecedores e outra para funcionários;
- Banco 2: Contém uma tabela chamada Pessoa, onde são armazenados os vários tipos de cadastros com dados em comum, como por exemplo cliente, fornecedor e funcionário (têm em comum: nome, endereço, telefone, CPF, etc.). Para cada novo registro na tabela Pessoa, deve-se informar o valor verdadeiro ou falso para os campos Cliente, Fornecedor e Funcionario. Essa estrutura evita que uma pessoa que seja cliente e funcionário ao mesmo tempo seja cadastrada mais de uma vez.
No decorrer do artigo será colocada em prática a criação de dois bancos com características do exemplo citado acima. Vamos nos referenciar a eles como sendo respectivamente o banco origem (contém os dados já cadastrados) e o banco destino (receberá a importação dos dados). Ambos os bancos serão criados em Firebird. Na verdade, poderíamos exemplificar com SGBDs (Sistema Gerenciador de Banco de Dados) diferentes, mas o foco do artigo está na estrutura diferente das tabelas. Usando apenas o Firebird tornamos a prática do artigo mais dinâmica. Além do mais, todo o controle de importação será feito na aplicação, ou seja, não depende do SGBD.
Após a criação dos bancos, o próximo passo será a aplicação. Nesta, iremos primeiramente adicionar um formulário simples para inserir alguns cadastros no banco origem. Em seguida, outro formulário irá controlar todo o processo de importação dos dados, analisando as condições e inserindo os dados através de DataSet´s.
Criando a origem
Criaremos primeiramente um banco de dados simples para usar de exemplo para a origem dos dados que queremos importar. Este terá apenas as tabelas Cliente, Dependente, Fornecedor e Funcionario. Sugiro que o banco seja criado em Firebird 2.0 e com a ferramenta IBExpert para execução dos scripts, mas como já foi dito, o SGDB fica a critério de cada um. A Listagem 1 mostra o script para criação do banco de dados origem.
A Listagem 2 traz um script opcional onde, para cada tabela, é criado um genaretor (Gen_Cliente_Id, Gen_Dependente_Id, etc.) e um trigger (T_Cliente_Bi, T_Dependente_Bi, etc.). O objetivo é gerar automaticamente o código da chave primária de cada tabela. Os triggers sempre serão disparados antes da confirmação de uma inserção (Active Before Insert) e irão atribuir a chave primária para a tabela respectiva, retornando o valor do generator.
Listagem 1. Script de criação do banco de dados origem
CREATE DATABASE 'C:\SISTEMAS\BANCOS\ORIGEM.FDB'
CREATE TABLE CLIENTE (
CLI_CODIGO INTEGER NOT NULL,
CLI_NOME VARCHAR(70) NOT NULL,
CLI_PESSOA_FJ CHAR(1) NOT NULL,
CLI_CPF_CNPJ VARCHAR(20) NOT NULL,
CLI_ENDERECO1 VARCHAR(70),
CLI_NUM_END1 VARCHAR(10),
CLI_BAIRRO1 VARCHAR(40),
CLI_CEP1 CHAR(10),
CLI_CIDADE1 VARCHAR(40),
CLI_UF1 CHAR(2),
CLI_ENDERECO2 VARCHAR(70),
CLI_NUM_END2 VARCHAR(10),
CLI_BAIRRO2 VARCHAR(40),
CLI_CEP2 CHAR(10),
CLI_CIDADE2 VARCHAR(40),
CLI_UF2 CHAR(2));
ALTER TABLE CLIENTE ADD CONSTRAINT PK_CLIENTE PRIMARY KEY (CLI_CODIGO);
CREATE GENERATOR GEN_CLIENTE_ID;
CREATE TRIGGER T_CLIENTE_BI FOR CLIENTE ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.CLI_CODIGO IS NULL) THEN
NEW.CLI_CODIGO = GEN_ID(GEN_CLIENTE_ID,1);
END
;
CREATE TABLE DEPENDENTE (
DEP_CODIGO INTEGER NOT NULL,
CLI_CODIGO INTEGER NOT NULL,
DEP_NOME VARCHAR(70) NOT NULL,
DEP_DATA_NASCIMENTO DATE
);
ALTER TABLE DEPENDENTE ADD CONSTRAINT PK_DEPENDENTE PRIMARY KEY (DEP_CODIGO)
USING INDEX PK_DEPENDENTE;
ALTER TABLE DEPENDENTE ADD CONSTRAINT FK_DEP_CLIENTE FOREIGN KEY (CLI_CODIGO)
REFERENCES CLIENTE(CLI_CODIGO)USING INDEX FK_DEP_CLIENTE;
CREATE GENERATOR GEN_DEPENDENTE_ID;
CREATE TRIGGER T_DEPENDENTE_BI FOR DEPENDENTE ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.DEP_CODIGO IS NULL) THEN
NEW.DEP_CODIGO = GEN_ID(GEN_DEPENDENTE_ID,1);
END
;
CREATE TABLE FORNECEDOR (
FOR_CODIGO INTEGER NOT NULL,
FOR_NOME VARCHAR(70) NOT NULL,
FOR_PESSOA_FJ CHAR(1) NOT NULL,
FOR_CPF VARCHAR(20) NOT NULL,
FOR_ENDERECO VARCHAR(70),
FOR_NUM_END VARCHAR(10),
FOR_BAIRRO VARCHAR(40),
FOR_CEP CHAR(10),
FOR_CIDADE VARCHAR(40),
FOR_UF CHAR(2)
);
ALTER TABLE FORNECEDOR ADD CONSTRAINT PK_FORNECEDOR PRIMARY KEY (FOR_CODIGO);
CREATE GENERATOR GEN_FORNECEDOR_ID;
CREATE TRIGGER T_FORNECEDOR_BI FOR FORNECEDOR ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.FOR_CODIGO IS NULL) THEN
NEW.FOR_CODIGO = GEN_ID(GEN_FORNECEDOR_ID,1);
END
;
CREATE TABLE FUNCIONARIO (
FUN_CODIGO INTEGER NOT NULL,
FUN_NOME VARCHAR(70) NOT NULL,
FUN_CPF VARCHAR(11) NOT NULL,
FUN_ENDERECO VARCHAR(70),
FUN_NUM_END VARCHAR(10),
FUN_BAIRRO VARCHAR(40),
FUN_CEP CHAR(10),
FUN_CIDADE VARCHAR(40),
FUN_UF CHAR(2),
FUN_CARGO VARCHAR(40),
FUN_SALARIO NUMERIC(12,2)
);
ALTER TABLE FUNCIONARIO ADD CONSTRAINT PK_FUNCIONRIO PRIMARY KEY (FUN_CODIGO);
CREATE GENERATOR GEN_FUNCIONARIO_ID;
CREATE TRIGGER T_FUNCIONARIO_BI FOR FUNCIONARIO ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.FUN_CODIGO IS NULL) THEN
NEW.FUN_CODIGO = GEN_ID(GEN_FUNCIONARIO_ID,1);
END
;
Listagem 2. Script opcional para criação de triggers no banco de dados origem
CREATE GENERATOR GEN_CLIENTE_ID;
CREATE GENERATOR GEN_DEPENDENTE_ID;
CREATE GENERATOR GEN_FORNECEDOR_ID;
CREATE GENERATOR GEN_FUNCIONARIO_ID;
CREATE TRIGGER T_CLIENTE_BI FOR CLIENTE
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.CLI_CODIGO IS NULL) THEN
NEW.CLI_CODIGO = GEN_ID(GEN_CLIENTE_ID,1);
END;
CREATE TRIGGER T_DEPENDENTE_BI FOR DEPENDENTE
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.DEP_CODIGO IS NULL) THEN
NEW.DEP_CODIGO = GEN_ID(GEN_DEPENDENTE_ID,1);
END;
CREATE TRIGGER T_FORNECEDOR_BI FOR FORNECEDOR
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.FOR_CODIGO IS NULL) THEN
NEW.FOR_CODIGO = GEN_ID(GEN_FORNECEDOR_ID,1);
END;
CREATE TRIGGER T_FUNCIONARIO_BI FOR FUNCIONARIO
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.FUN_CODIGO IS NULL) THEN
NEW.FUN_CODIGO = GEN_ID(GEN_FUNCIONARIO_ID,1);
END;
...