sábado, 3 de mayo de 2014

Pasar datos de una tabla a otra de distinta base de datos

En algunas ocasiones es necesario migrar datos desde una tabla de una base de datos a otra tabla de otra base de datos diferente. En este caso he considerado que las tablas son iguales pero hay que tener en cuenta que si son diferentes habrá que tener cuidado con que campos se migran a que campos, que longitud y tipo tienen estos.

Hay un método algo complicado pero muy potente que ya se explicó anteriormente  que es creando un cursor.

Creamos un cursor que recorra la tabla de origen y si el registro NO existe en la tabla de destino lo insertamos con un INSERT-SELECT si ya existe no hacemos nada.
SI la tabla tiene dependencias tendremos que dar de alta los registros de las tablas dependientes que no existan en el destino. Buscamos las dependencias de las tablas con sp_help.

sp_help 'dbo.tbclientes'


En la 7ª salida podemos ver las referencias externas a otras tablas.

sp_help traspaso base de datos

Tiene referencias en otras tablas como tbMunicipios  por tanto, si se va a hacer un INSERT-SELECT de un registro y sólo en ese caso comprobamos antes si el código del municipio que se va a introducir en nuestra tabla de clientes ya existe en la tabla de municipios, si es así inserta solo el cliente, en caso contrario debe insertar también el municipio con un INSERT-SELECT anidado al de clientes, para el resto de tablas se procede de la misma forma.
Si las tablas referenciadas a su vez tuvieran  otras sería necesario ir anidando bucles.
Un ejemplo de cursor y su bucle anidado podría ser este:

insert into dbo.tbclientes select * from dbBASE_DATOS_EXTERNA.dbo.tbclientes
--BUCLE DE CLIENTES
--La clave única es el NIF
begin transaction
    -- declaramos las variables
      DECLARE @NIF as nvarchar(14)
      DECLARE @i as integer --Contador

--Declaración del cursor.
declare clientes INSENSITIVE cursor for
--búsqueda de la clave
select strNIf from dbBASE_DATOS_EXTERNA.dbo.tbclientes
open clientes
--Comienzo del blucle
SELECT @i = @@CURSOR_ROWS

-- Avanzamos un registro y cargamos en las variables los valores encontrados en el primer registro
fetch next from clientes into @NIF
            WHILE @i > 0
            BEGIN
                  SELECT @i = @i - 1
                        --si el registro ya existe no lo inserto, si no existe count = 0, lo inserto
                IF (select count(*) from dbo.tbclientes  where strNIF = @NIF) = 0

--Antes de hacer el INSER_SELECT definitivo recorremos en bucles
--anidados las tablas dependientes para
--insertar las filas necesarias que no estén dadas de alta
--bucle para la la tabla tbMunicipios
-- AQUÍ IRIA OTRO CURSOR PARA INSERTAR LA TABLA DE MUNICIPIOS
-- **********************************************************
--fin de bucle tabla tbMunicipios

      --Hacemos un INSERT SELECT de una tabla a otra.
                             SELECT * INTO dbBASE_DATOS_EXTERNA.dbo.tbclientes
                             FROM dbo.tbclientes
                             WHERE strNIF = @NIF
                        -- Avanzamos otro registro
                  fetch next from clientes into @NIF
            END
    -- cerramos el cursor
close clientes
deallocate clientes
commit  Transaction

Pero antes de complicarnos tanto la vida podemos comprobar si realmente serán necesarios todos esos bucles anidados.

Unas SELECT previas que nos ahorran mucho trabajo


Para evitar meternos en un código infinito que acabe migrando todas las tablas de la base de datos (lo más probable en muchas bases de datos) podemos hacer un estudio sobre datos reales de los datos que habrá que insertar realmente, no sea que perdamos mucho tiempo en programar bucles por los que luego no pasará nunca. (Aquí también hay que tener un poco de sentido común)

Select * from dbBASE_DATOS_EXTERNA.dbo.tbClientes where strNif not in (Select strNif from DBO.tbClientes)

Con esta primera select obtenemos todos los clientes de la BBDD_PRUEBA que no existen en la REAL.

Para datos anidados tendríamos que hacer esto:

Select * from dbBASE_DATOS_EXTERNA.dbo.tbClientes where strCMunicipio not in (select strCodigoMunicipio from dbo.tbMunicipios)
Select * from dbBASE_DATOS_EXTERNA.dbo.tbClientes where strTipoVia not in (select strTipo from dbo.tbTiposVia)
Select * from dbBASE_DATOS_EXTERNA.dbo.tbClientes where strFormaPago not in (select strFormaPago from dbo.tbFormasPago)
Select * from dbBASE_DATOS_EXTERNA.dbo.tbClientes where strGrupoComision not in (select strGrupoComision from dbo.tbGrupoComision)

Si esta selects no devuelven datos no es necesario programar los bucles anidados asociados a la tabla en cuestión.
Si alguna de estas selects devolviera datos habría que anidar un cursor completo dentro del bucle del cursor principal.

Las mismas select para proveedores son estas:

Select * from dbBASE_DATOS_EXTERNA.dbo.tbProveedores where strNif not in (Select strNif from DBO.tbProveedores)
Select * from dbBASE_DATOS_EXTERNA.dbo.tbProveedores where strNIF not in (select strNif from dbo.tbClientes)

En este caso si hay un subbucle pero como corresponde a la tabla de Clientes lo podemos obviar, en definitiva para hacerlo correcto podemos anidar el bucle de los clientes dentro del bucle de los proveedores y dejarlo todo en un único script.

Para evitar problemas primero pasamos el bucle que mete los clientes pues sabemos que no tiene problemas de tablas dependientes y luego el de proveedores.
Pero no es necesario complicarse tanto la vida con cursores ni bucles, hay una forma mucho más sencilla con subselects y con insert-selects.

Begin tran
INSERT INTO DBO.tbclientes SELECT * FROM dbBASE_DATOS_EXTERNA.dbo.tbClientes WHERE strNif not in (SELECT strNif FROM DBO.tbClientes)
INSERT INTO DBO.tbProveedores SELECT * FROM dbBASE_DATOS_EXTERNA.dbo.tbProveedores WHERE strNif not in (SELECT strNif FROM DBO.tbProveedores)
Commit tran

Si todo ha ido bien, ejecutar commit tran para cerrar la transacción
Para asegurarse de que todo ha ido bien, las selects de abajo no deberán devolver ningún registro.

--Cuando se ejecute el script estas select no deben devolver registros
Select * from dbBASE_DATOS_EXTERNA.dbo.tbClientes where strNif not in (Select strNif from dbo.tbClientes)
--selects para los bucles de Clientes
Select * from dbBASE_DATOS_EXTERNA.dbo.tbClientes where strCMunicipio not in (select strCodigoMunicipio from dbo.tbMunicipios)
Select * from dbBASE_DATOS_EXTERNA.dbo.tbClientes where strTipoVia not in (select strTipo from dbo.tbTiposVia)
Select * from dbBASE_DATOS_EXTERNA.dbo.tbClientes where strFormaPago not in (select strFormaPago from dbo.tbFormasPago)
Select * from dbBASE_DATOS_EXTERNA.dbo.tbClientes where strGrupoComision not in (select strGrupoComision from dbo.tbGrupoComision)
--selects para bucles de Proveedores
Select * from dbBASE_DATOS_EXTERNA.dbo.tbProveedores where strNif not in (Select strNif from dbo.tbProveedores)
Select * from dbBASE_DATOS_EXTERNA.dbo.tbProveedores where strNIF not in (select strNif from dbo.tbClientes)



No hay comentarios:

Publicar un comentario