jump to navigation

Actualizacion – Copiar datos entre tablas marzo 2, 2007

Posted by superpiwi in Java.
2 comments

Con respecto al post

copiar tablas entre bases de datos

he ampliado la funcionalidad de las clases para poder generar el script SQL con las sentencias insert y permite ahora guardarlas en un fichero. Esto nos permite por ejemplo ejecutarlas a posteriori mediante sqlplus:

sqlplus @<fichero.sql>

Los cambios son los siguientes:

Se añade la siguiente variable a la clase DatabaseUtil.java

/**
* Token_final para sentencias SQL
*/
String END_SQL=";";

Y añadimos el metodo:


/**
* Genera el DML de insercion de una tabla. (para utilizar con sqlplus @fichero.sql)
* @param tablename nombre de la tabla.
* @param source conexion con la base de datos.
* @param deleteTarget indica si se debe o no incluir la sentencia DELETE.
* @param out Fichero donde guardar (no se utiliza)
* @throws Exception excepcion levantada en caso de error.
*/
public String generarSQL(String tablename, Connection source, boolean deleteTarget,FileOutputStream out)
throws Exception
{
StringBuffer sql = new StringBuffer();
ResultSet rs = null;
Statement stmt = null;
ResultSetMetaData metadata = null;
String[] columnas = null;
Vector valores = null;
//Vector SENTENCIAS_A_EJECUTAR = null;
Statement stmt2 = null;
String tablename2 = null;
int[] resultados=null;
try
{
// invocar al recolector de basura
System.gc();
long time = System.currentTimeMillis();
DatabaseUtil.debug(DatabaseUtil.class.getName(), "generarSQL", "Generando SQL...", 6, null, null);
sql.append("\r\n-- Generado con DatabaseUtil -- TABLENAME: "+tablename+"\r\n\r\n");
tablename2 = tablename;
// crear conexion con el origen.
DatabaseUtil.debug(DatabaseUtil.class.getName(), "generarSQL", "creando conexion con el origen...", 6, null, null);
try
{
stmt = source.createStatement();
}
catch(Exception e)
{
String error = e.getMessage();
DatabaseUtil.error(DatabaseUtil.class.getName(), "generarSQL", "No se pudo establecer la conexion con el origen : "+error, 6, null, null);
throw new Exception("No se pudo establecer la conexion origen : "+error);
}
DatabaseUtil.debug(DatabaseUtil.class.getName(), "generarSQL", "creando origen creada...", 6, null, null);
// Contabilizar el numero de registros
String SENTENCIA_SQL = "SELECT COUNT(*) FROM "+tablename;
rs = stmt.executeQuery(SENTENCIA_SQL);
rs.next();
String numero_registros = rs.getString(1);
if (rs!=null) rs.close();
// TODO: cambiar esta parte pq funciona pero no es adecuada, hay una clase que nos devuelve el metadato de columnas de una tabla
// sin necesidad de emplear el SELECT * sino directamente analizando el esquema de la base de datos
// ejecutar la consulta para recuperar los nombres de las columnas.
SENTENCIA_SQL = "SELECT * FROM "+tablename;
rs = stmt.executeQuery(SENTENCIA_SQL);
// recuperamos los metadatos
metadata = rs.getMetaData();
int numero_columnas = metadata.getColumnCount();
DatabaseUtil.debug(DatabaseUtil.class.getName(), "generarSQL", "La tabla tiene "+numero_columnas+" columnas", 6, null, null);
// las almacenamos en un Array de Strings.
columnas = new String[numero_columnas];
for (int i=1; i<=numero_columnas;i++)
{
String columna = metadata.getColumnName(i);
columnas[i-1] = columna;
}
// Construimos las sentencias INSERTs para la otra tabla destino...
//SENTENCIAS_A_EJECUTAR = new Vector();
if (deleteTarget)
{
String DELETE = "DELETE FROM "+tablename2+this.END_SQL;
//sql.append(DELETE);
//SENTENCIAS_A_EJECUTAR.addElement(DELETE);
System.out.println(DELETE);
DELETE=DELETE+"\r\n";
if (out!=null) out.write(DELETE.getBytes());
}
while (rs.next())
{
String INSERT = "INSERT INTO "+tablename2+"(";
// recuperamos el valor de todos los registros...
valores = new Vector();
for (int j=1;j<=numero_columnas;j++)
{
INSERT=INSERT+""+columnas[j-1]+",";
String dato = rs.getString(columnas[j-1]);
if (dato==null) dato="";
if (dato!=null)
{
// esto se hace para evitar errores a la hora de insertar campos numericos.
if (dato.equals("null")) dato="";
}
valores.add(dato);
}
//end for
if (INSERT.endsWith(",")) INSERT=INSERT.substring(0,INSERT.length()-1);
INSERT=INSERT+") VALUES (";
// Insertamos los valores...
for (int k=0;k<valores.size();k++)
{
String valor = (String) valores.elementAt(k);
//
// BUG: se evita la insercion de valores que contengan "'" para ello se escapa el campo "''".
//
//valor = Replacement.escape(valor);
INSERT = INSERT+"'"+valor+"',";
}
if (INSERT.endsWith(",")) INSERT=INSERT.substring(0,INSERT.length()-1);
INSERT=INSERT+")";
// String tenemos la sentencia INSERT que almacenamos el el vector de sentencias...
//sql.append(INSERT+this.END_SQL);
//SENTENCIAS_A_EJECUTAR.addElement(INSERT+this.END_SQL);
INSERT = INSERT+this.END_SQL;
System.out.println(INSERT);
INSERT = INSERT+"\r\n";
if (out!=null) out.write(INSERT.getBytes());
}
long time_end = System.currentTimeMillis();
long total = time_end - time;
String tiempo = tablename+", Time: "+total+" ms";
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", tiempo, 6, null, null);
sql.append("\r\n--generado con DatabaseUtil, "+tiempo+"\r\n");
String SQL_ALL = sql.toString();
return SQL_ALL;
}
catch(Exception e)
{
DatabaseUtil.error(DatabaseUtil.class.getName(), "generarSQL", "Ha ocurrido un error ejecutando proceso Batch para la tabla "+tablename, 6, null, null);
DatabaseUtil.error(DatabaseUtil.class.getName(), "generarSQL", e.toString(), 6, null, null);
throw e;
}
finally
{
// cerramos los flujos abiertos
try
{
if (rs!=null) rs.close();
}
catch(Exception e)
{
;
}
try
{
if (stmt!=null) stmt.close();
}
catch(Exception e)
{
;
}
try
{
if (stmt2!=null) stmt2.close();
}
catch(Exception e)
{
;
}
}
}
//----

Sobre la clase Migracion.java añadimos el metodo:


/**
* @modification - <<AÑADIDO 1 MARZO>> Para generar el SQL de las sentencias
* Genera el SQL de migracion de las tablas.
* @param out fichero donde guardar las sentencias para posteriormente ejecutar con sqlplus @nombrefichero.sql
* @return un SQL con las sentencias DDL de insercion de las tablas (si esta habilitado aunque no se recomienda por problemas de memoria) + 1 informe de tiempos.
* @throws Exception excepcion levantada en caso de error.
*/
public String generarSQL(FileOutputStream out) throws Exception
{
StringBuffer sbsql = new StringBuffer();
Connection ORIGEN=null;
DatabaseUtil util = null;
try
{
imprimirParametros();
Migracion.debug(Migracion.class.getName(), "migrar", "@obtener conexiones", 6, null, null);
Class.forName(this.odriver);
ORIGEN=DriverManager.getConnection(this.ourl,this.ouser,this.opass);
Migracion.debug(Migracion.class.getName(), "migrar", "conexion origen:"+ORIGEN, 6, null, null);
Class.forName(this.ddriver);
Migracion.debug(Migracion.class.getName(), "migrar", "@Procesar tablas", 6, null, null);
util = new DatabaseUtil();
util.setVerbose(verbose);
// obtener tablas
StringTokenizer st = new StringTokenizer(this.otables,",");
while (st.hasMoreTokens())
{
String TABLENAME = st.nextToken();
Migracion.debug(Migracion.class.getName(), "migrar", "Procesando tabla:"+TABLENAME+"...", 6, null, null);
// recuperar el SQL
String SQL = util.generarSQL(TABLENAME, ORIGEN, true, out);
sbsql.append(SQL);
}
return sbsql.toString();
}
catch(Exception e)
{
throw e;
}
finally
{
try
{
if (ORIGEN!=null) ORIGEN.close();
}
catch(Exception f)
{
;
}
}
}
//----

Ahora si queremos guardar en disco las sentencias SQL bastaria con invocar:


Migracion m2 = new Migracion(...lo que sea...)...
File fout = new File("/home/jose/Desktop/migracion.sql");
FileOutputStream fo = new FileOutputStream(fout);
String SQL_TABLAS = m2.generarSQL(fo);
System.out.println(SQL_TABLAS);
fo.close();

Puede que no sea lo mas optimo pero funciona.