domingo, febrero 25, 2018

VFP: Cómo mover una tabla de una Base de Datos a otra

En ocasiones puede pasar que tengamos una tabla que inicialmente pertenece a una base de datos, pero que luego por algún motivo necesitemos quitarla de esa base de datos y moverla a otra distinta con todos sus datos.

A priori esto puede parecer algo sencillo, pero dependiendo de algunas circunstancias puede ser bastante más complicado.

Veamos algunos ejemplos, para los que VFP debe estar ubicado en el directorio de los datos.
Recordar siempre hacer un backup antes!




Caso 1: Tabla con nombres de campo cortos (hasta 10 caracteres) y sin triggers


Supongamos por ejemplo que tenemos una "tabla1" con un campo "NOMBRE" y un índice por el mismo, perteneciente a la base de datos BDD1

En este caso la operación es sencilla, basta con quitar la tabla de una base de datos y agregarla a la otra base de datos:


1) Para definir una situación inicial de ejemplo, creamos una BDD1 con una Tabla1 con datos e índice (en un caso real ir directo al paso 2):

CREATE DATABASE bdd1
CREATE TABLE tabla1 (nombre c(30))
INSERT INTO tabla1 (nombre) VALUES ("Francisco")
INSERT INTO tabla1 (nombre) VALUES ("Antonio")
INSERT INTO tabla1 (nombre) VALUES ("Juan")
INDEX on nombre TAG nombre
CLOSE ALL


2) Ahora movemos la tabla a la otra BDD:

OPEN DATABASE bdd1 EXCLUSIVE && Abrimos la BDD origen 
REMOVE TABLE tabla1          && Quitamos la tabla de la misma 
OPEN DATABASE bdd2 EXCLUSIVE && Abrimos la BDD destino
ADD TABLE tabla1             && Agregamos la tabla
CLOSE ALL


Listo! Esta opción es la más simple y rápida, y no implica trasvasar datos.




Caso 2: Tabla con nombres de campo largos (más de 10 caracteres) y sin triggers


Ahora supongamos por ejemplo que tenemos una "tabla1" con un campo "NOMBRE_LARGO" y un índice por el mismo, perteneciente a la base de datos BDD1

En este caso la operación sigue siendo sencilla, aunque no podremos seguir los pasos del Caso 1 porque perderemos los nombres largos y los índices que dependan de ellos dejarán de funcionar.


1) Para definir una situación inicial de ejemplo, creamos una BDD1 con una Tabla1 con datos e índice (en un caso real ir directo al paso 2):

CREATE DATABASE bdd1CREATE TABLE tabla1 (nombre_largo c(30))
INSERT INTO tabla1 (nombre_largo) VALUES ("Francisco")
INSERT INTO tabla1 (nombre_largo) VALUES ("Antonio")
INSERT INTO tabla1 (nombre_largo) VALUES ("Juan")
INDEX on nombre_largo TAG nombre
CLOSE ALL


2) Ahora movemos la tabla a la otra BDD en un directorio de trabajo y traemos todo lo hecho:

MKDIR copia                     && Creamos un dir de trabajo
COPY FILE BDD2.* TO copia\*.*   && Copiamos la BDD destino
USE tabla1 EXCLUSIVE

COPY STRUCTURE TO copia\tabla1 ;&& Copiamos la estructura de la
   WITH CDX DATABASE copia\BDD2 && tabla y CDX a la BDD destino
CLOSE ALL
OPEN DATABASE copia\bdd2 EXCLU  && Abrimos la BDD destino
USE copia\tabla1 EXCLUSIVE

APPEND FROM tabla1              && Recuperamos los datos originales
CLOSE ALL
OPEN DATABASE bdd1 EXCLUSIVE    && Abrimos la BDD origen
REMOVE TABLE tabla1             && Quitamos la tabla de la misma
CLOSE ALL 
COPY FILE copia\*.* TO *.*      && Traemos los archivos modificados


Terminado! Esta opción es la más simple y rápida, aunque implica trasvasar datos.




Caso 3: Tabla con propiedades de BDD


Otro caso que se puede presentar es tener una tabla asociada a una BDD que use propiedades específicas de esta, como reglas de validación de campos, mensajes de validación, comentarios de tabla o campos, triggers, etc.

Este caso es uno de los más complejos, porque si seguimos los pasos del Caso 1, perderemos los nombres largos y los índices que dependan de ellos dejarán de funcionar., y si seguimos los pasos del  Caso 2 tendremos los datos y los índices, pero no las propiedades de BDD comentadas.

Aquí se podría usar FoxBin2Prg, pero en este caso es necesario conocer las estructuras DB2 (tabla) y DC2 (base de datos) generadas, ya que habrá que cortar y pegar algunas secciones del DBC1 para pasarlos al DBC2, además de modificar el DB2.

Vamos a ver un ejemplo con la misma tabla que el Caso 2 y algunas propiedades de BDD.


1) Para definir una situación inicial de ejemplo, creamos una BDD1 con una Tabla1 con datos, índice y algunas propiedades de BDD (en un caso real ir directo al paso 2):

CREATE DATABASE bdd1
CREATE TABLE tabla1 ;
    ( nombre_largo C(30) ;
    CHECK NOT EMPTY(nombre_largo) ;
    ERROR "El nombre no puede estar vacío" ;
    , codigo I AUTOINC NEXTVALUE 1 STEP 1 ;
    PRIMARY KEY )

INSERT INTO tabla1 (nombre_largo) VALUES ("Francisco")
INSERT INTO tabla1 (nombre_largo) VALUES ("Antonio")
INSERT INTO tabla1 (nombre_largo) VALUES ("Juan")
INDEX on nombre_largo TAG nombre
DBSETPROP("tabla1.nombre_largo","FIELD","Comment";
    ,"Comentario del campo nombre_largo")
DBSETPROP("tabla1","TABLE","Comment","Comentario de la tabla")
CLOSE ALL



2) Creamos un archivo de configuración específico para nuestra Tabla1 (tabla1.dbf.cfg) con esta configuración:

DBF_Conversion_Support: 8 && Permite exportar e importar estructura, indices y datos


3) Creamos la vista de texto (DB2) de esta Tabla, la vista de texto (DC2) de su base de datos BDD1 y la vista de texto (DC2) de la base de datos destino BDD2 con FoxBin2Prg


4) Si abrimos la vista de texto de la tabla del ejemplo (tabla1.db2), veremos que tiene dentro toda la información de la estructura al principio y luego los registros de datos. En esta cabecera debemos cambiar el nombre de la base de datos actual (BDD1) por la que queremos que sea la nueva (BDD2) y lo volvemos a guardar:

<TABLE>
    <MemoFile></MemoFile>
    <CodePage>1252</CodePage>
    <LastUpdate></LastUpdate>
    <Database>bdd2.dbc</Database>



5) Si abrimos la vista de texto de la base de datos del ejemplo (bdd1.dc2), veremos que figuran todas las tablas con una estructura como esta:

<DATABASE>
    <Name>BDD1</Name>
    <Comment></Comment>
    <Version>10</Version>
    <DBCEvents>.F.</DBCEvents>
    <DBCEventFilename></DBCEventFilename>

    <TABLES>

        <TABLE>
            <Name>TABLA1</Name>
            <Comment>Comentario de la tabla</Comment>
            <Path>tabla1.dbf</Path>

            ... 
        </TABLE>


Los tags <TABLE></TABLE> contienen toda la información de cada tabla, sus campos, índices y comentarios, parte de los cuales están repetidos en la información de la tabla.


6) La sección completa <TABLE></TABLE> de la tabla que nos interesa pasar, la cortamos de esta estructura y la pegamos en la estructura de destino (bdd2.dc2), cuidando de insertarla en orden alfabético por el nombre de la tabla (el tag <NAME>), y guardando el cambio en ambos archivos (bdd1.dc2 y bdd2.dc2)

Nota: Si la base de datos bdd2 es nueva, no tendrá tablas dentro por lo que la estructura externa <TABLES></TABLES> que contiene la tablas tampoco existirá, por lo que podría haber que crearla manualmente, ya que estamos pasando solo una tabla.


7) Abrimos el archivo de la base de datos origen (bdd1.dc2) con FoxBin2Prg para que regenere el DBC sin la Tabla1


8) Abrimos el archivo de la tabla (tabla1.db2) con FoxBin2Prg para que la regenere con su nueva base de datos referenciada


9) Abrimos el archivo de la base de datos destino (bdd2.dc2) con FoxBin2Prg para que regenere el DBC con la nueva información de la Tabla1


¡Al fin! Ya tenemos pasada la tabla1 de la bdd1 a la bdd2 con toda su información relacionada.




Resumen:


Hay otras formas de pasar una tabla a otra base de datos, pero normalmente requieren usar programación específica para dichos casos y tener un conocimiento más técnico y profundo de cada componente.

Lo que he querido mostrar en este caso es una forma genérica que sirve con cualquier tabla y cualquier base de datos, donde todo se reduce a cortar/pegar algunas secciones de un archivo de texto a otro y dejar que FoxBin2Prg se encargue de la parte técnica.

Nota importante sobre triggers: Se debe tener en cuenta que cuando hay triggers de por medio, si bien FoxBin2Prg puede pasar la información de una BDD a otra, este caso sí requiere tener conocimientos de los mismos y de procedimientos almacenados, ya que aunque se pase automáticamente la información de la tabla y sus metadatos, no será igual con los procedimientos almacenados, los cuáles habrá que seleccionar cuidadosamente y pasar también a la base de datos de destino, pero además de esto se debe considerar si es posible hacer esta mudanza de base de datos, porque normalmente los triggers vinculan tablas (ej; si se borra o actualiza en una que se borre o actualice en cascada en otras) y es muy probable que eso implique o bien quitar triggers o bien mover varias tablas en conjunto.


Hasta la próxima! :D