Actualización de la versión de la base de datos

¿Cómo modificamos la versión de la base de datos de nuestra aplicación sin perder datos?

Puede que una vez finalizada la aplicación sea necesario alterar la estructura de la base de datos. Por ejemplo añadiendo una nueva columna a una tabla.

Dicho control de versiones se lleva a cabo en el método onUpgrade dentro de la clase que extiende a SQLiteOpenHelper.

En el ejemplo Almacen mostrado, dicho método se encuentra en DatabaseHelper_almacen.java. En un principio dicho método lo que hace es borrar la tabla y llamar al método onCreate. De esta manera, perderíamos todos los datos que tuviéramos almacenados.

// Es llamado desde SQLiteOpenHelper cuando se detecta cambio de versiones
// Borra la tabla almacen y la vuelve a crear.
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
	android.util.Log.v("BBDD",
			"BD actualizándose. Se perderán los datos antiguos");
	db.execSQL("DROP TABLE IF EXISTS " + tabla + " ;");
	onCreate(db);
}

Imaginemos que queremos subir a versión 2, declarándolo así

private static final int DATABASE_VERSION = 2;

Al detectar cambio de versión, el método onUpgrade es llamado. Por ejemplo podemos rellenarlo de la siguiente manera. En el caso de que la antigua versión sea 1 y la nueva sea 2, llamamos a una función que se encarga de actualizar a versión 2. Dicha función (actualiza_a_2) se encarga de mostrar en el Log el cambio de versión y borrar todas aquellas entradas de la base de datos cuyo producto no tenga un nombre asociado.

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
	//Actualizamos a versión 2
	if (oldVersion == 1 && newVersion==2){
		actualiza_a_2(db);
	}
}
/**
 * En esta actualización borramos todos aquellos productos que no tengan un nombre asociado	
 * @param db
 */
private void actualiza_a_2(SQLiteDatabase db) {
	android.util.Log.v("BBDD",
			"Actualizamos a versión 2");
	db.execSQL("DELETE FROM " + tabla + " WHERE " + NOMBRE + " = '' ;");
}

En el caso de necesitar una tercera actualización a versión 3 para añadir una nueva columna llamada precio a la tabla modificamos el método onUpgrade de la siguiente manera.

private static final int DATABASE_VERSION = 3;
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
	// Actualizamos a versión 2
	if (oldVersion == 1 && newVersion == 2) {
		actualiza_a_2(db);
	}
	if (oldVersion >= 1 && newVersion == 3) {
		actualiza_a_3(db);
	}
}

En la función actualiza_a_3 incluimos la sentencia sql para añadir la nueva columna

/**
 * Versión 3
 * En esta actualización añadimos una columna de precio a la tabla
 * @param db
 */
private void actualiza_a_3(SQLiteDatabase db) {
	android.util.Log.v("BBDD", "Actualizamos a versión 3");
	db.execSQL("ALTER TABLE " + tabla + " ADD " + PRECIO + " REAL CHECK ( "
			+ PRECIO + " > 0 );");
}

Esta modificación es necesaria incluirla en el método onCreate, ya que si la primera versión que se instala es la 3, perdemos este cambio.

@Override
public void onCreate(SQLiteDatabase db) {
	// Creamos la tabla almacen con 4 columnas
	db.execSQL("CREATE TABLE " + tabla
			+ " (_id INTEGER PRIMARY KEY AUTOINCREMENT, " + NOMBRE
			+ " TEXT," + CANTIDAD + " INTEGER CHECK (" + CANTIDAD
			+ ">=0), " + DESCRIPCION + " TEXT);");

        // Añadimos la modificación de la versión 3
	db.execSQL("ALTER TABLE " + tabla + " ADD " + PRECIO + " REAL CHECK ( "
			+ PRECIO + " > 0 );");
}

Tras todas estas modificaciones, la clase DatabaseHelper_almacen.java quedaría como sigue:

package com.example.almacen;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DatabaseHelper_almacen extends SQLiteOpenHelper {

	private static final String DATABASE = "ALMACEN_DB.db";
	private static final int DATABASE_VERSION = 3;
	public static final String tabla = "almacen";
	public static final String ID = "_id";
	public static final String NOMBRE = "nombre";
	public static final String CANTIDAD = "cantidad";
	public static final String DESCRIPCION = "descripcion";
	public static final String PRECIO = "precio";

	// Constructor.
	// Toma el contexto, el nombre de la base de datos y la versión de ésta.
	// El tercer parámetro se usa para crear objetos cursor que en nuestro caso
	// no utilizaremos y los rellenamos con null
	public DatabaseHelper_almacen(Context context) {
		super(context, DATABASE, null, DATABASE_VERSION);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		// Creamos la tabla almacen con 4 columnas
		db.execSQL("CREATE TABLE " + tabla
				+ " (_id INTEGER PRIMARY KEY AUTOINCREMENT, " + NOMBRE
				+ " TEXT," + CANTIDAD + " INTEGER CHECK (" + CANTIDAD
				+ ">=0), " + DESCRIPCION + " TEXT);");

		// Añadimos la modificación de la versión 3
		db.execSQL("ALTER TABLE " + tabla + " ADD " + PRECIO + " REAL CHECK ( "
				+ PRECIO + " > 0 );");
	}

	// Es llamado desde SQLiteOpenHelper cuando se detecta cambio de versiones
	// Borra la tabla almacen y la vuelve a crear en la versión 1.
	// En el caso de que la antigua versión sea 1 y la nueva 2, llama a
	// actualiza_a_2
	// En el caso de que la antigua versión sea 1 o 2 y la nueva sea 3, llama a
	// actualiza_a_3
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// android.util.Log.v("BBDD",
		// "BD actualizándose. Se perderán los datos antiguos");
		// db.execSQL("DROP TABLE IF EXITS " + tabla + " ");

		// Actualizamos a versión 2
		if (oldVersion == 1 && newVersion == 2) {
			actualiza_a_2(db);
		}
		if (oldVersion >= 1 && newVersion == 3) {
			actualiza_a_3(db);
		}
	}

	/**
	 * Versión 3
	 * En esta actualización añadimos una columna de precio a la tabla
	 * @param db
	 */
	private void actualiza_a_3(SQLiteDatabase db) {
		android.util.Log.v("BBDD", "Actualizamos a versión 3");
		db.execSQL("ALTER TABLE " + tabla + " ADD " + PRECIO + " REAL CHECK ( "
				+ PRECIO + " > 0 );");
	}

	/**
	 * Versión 2
	 * En esta actualización borramos todos aquellos productos que no tengan un
	 * nombre asociado
	 * @param db
	 */
	private void actualiza_a_2(SQLiteDatabase db) {

		android.util.Log.v("BBDD", "Actualizamos a versión 2");
		db.execSQL("DELETE FROM " + tabla + " WHERE " + NOMBRE + " = '' ;");
	}

}

mónica