ejemplo base de datos sqlite (android)

9
Introducción El gestor de bases de datos por defecto de Android es Lite. SQLite es una base de datos transaccional ligera que ocupa una cantidad muy pequeña de espacio en disco y memoria, de manera que es la elección perfecta para crear bases de datos en sistemas operativos para móviles como Android o iOS. Aspectos a tener en cuenta cuando se maneja SQLite: 1. SQLite no dispone de control de integridad, por lo que puedes almacenar un valor de un cierto tipo en un campo de otro tipo distinto (por ejemplo poner un string e un integer o viceversa) 2. SQLite no gestiona directamente la integridad referencial, no soporta restricciones FOREIGN KEY (clave externa) ni sentencias JOIN. No obstante, se puede controlar mediante triggers. 3. El soporte completo de Unicode es opcional y no está instalado por defecto. En este tutorial crearemos una base de datos simple para almacenar la información básica de una serie de empleados. La base de datos dispone de: Tablas 1. TEmpleados 2. TDepartamentos Vistas 1. vistaEmpleados: para visualizar los empleados y los departamentos de la empresa relacionados a los que pertenecen.

Upload: mejiaff

Post on 18-Nov-2014

60.378 views

Category:

Documents


1 download

DESCRIPTION

Describ

TRANSCRIPT

Page 1: Ejemplo Base de Datos SQLite (Android)

Introducción

El gestor de bases de datos por defecto de Android es Lite. SQLite es una base de datos

transaccional ligera que ocupa una cantidad muy pequeña de espacio en disco y

memoria, de manera que es la elección perfecta para crear bases de datos en sistemas

operativos para móviles como Android o iOS.

Aspectos a tener en cuenta cuando se maneja SQLite:

1. SQLite no dispone de control de integridad, por lo que puedes almacenar un

valor de un cierto tipo en un campo de otro tipo distinto (por ejemplo poner un

string e un integer o viceversa)

2. SQLite no gestiona directamente la integridad referencial, no soporta

restricciones FOREIGN KEY (clave externa) ni sentencias JOIN. No obstante, se

puede controlar mediante triggers.

3. El soporte completo de Unicode es opcional y no está instalado por defecto.

En este tutorial crearemos una base de datos simple para almacenar la información

básica de una serie de empleados. La base de datos dispone de:

Tablas

1. TEmpleados

2. TDepartamentos

Vistas

1. vistaEmpleados: para visualizar los empleados y los departamentos de la

empresa relacionados a los que pertenecen.

Page 2: Ejemplo Base de Datos SQLite (Android)

Creación de la base de datos SQL

Por defecto, SQLite no dispone de una interfaz gráfica que lo maneje o una aplicación

para gestionar los formularios de la base de datos, por lo que debemos crear nosotros

mismos las bases de datos mediante código. Primeramente, crearemos una clase que

lleve a cabo todas las operaciones necesarias para tratar la base de datos, tales como

crear tablas o insertar y borrar registros. Esa clase será una clase derivada de

SQLiteOpenHelper. Tendremos que sobrecargar los métodos apropiados, en cada

caso, para llevar a cabo la operación deseada. Sólo dispone de dos:

1. onCreate(SQLiteDatabase db): es invocado cuando se crea la base de datos,

esto es, cuando creas tablas, campos, vistas o triggers.

2. onUpgrade(SQLiteDatabse db, int oldVersion, int newVersion): es

invocado cuando se lleva a cabo una modificación de la base de datos, como

alterar, borrar o crear nuevas tablas.

Nuestra clase tendrá los siguientes campos:

public class BaseDeDatos extends SQLiteOpenHelper {

static final String nombreBD="BDtrabajadores";

static final String tablaEmpleados="TEmpleados";

static final String colID="idEmpleado";

static final String colNombre="nombreEmpleado";

static final String colEdad="edad";

static final String colDept="departamento";

static final String tablaDepartamentos="TDepartamentos";

static final String colDeptID="idDept";

static final String colDeptNombre="nombreDept";

static final String vistaEmps="vistaEmpleados";

El constructor

public BaseDeDatos(Context context) {

super(context, nombreBD, null,33);

}

El contructor de la superclase tiene los siguientes parámetros:

Context con: el contexto asociado a la base de datos

nombreBD: el nombre de la base de datos

CursorFactory: a veces, podemos usar una clase que extiende la clase Cursor

para implementar algunas validaciones extra u operaciones sobre las consultas a

la base de datos. Si así fuera, pasaríamos una instancia de la clase

CursorFactory para devolver una referencia a nuestra clase derivada para ser

utilizada en lugar del cursor por defecto. En este ejemplo, usaremos la interface

Page 3: Ejemplo Base de Datos SQLite (Android)

Cursor por defecto para recoger los resultados de las consultas, por lo que el

parámetro es null.

Version: la versión del esquema de la base de datos. El constructor crea una

base de datos en blanco con el nombre y el número de versión especificados.

Creando la base de datos

El primer método de la superclase que debemos sobrecargar es

onCreate(SQLiteDatabase db):

@Override

public void onCreate(SQLiteDatabase bd) {

bd.execSQL("CREATE TABLE "+tablaDepartamentos+" ("+colDeptID+ "

INTEGER PRIMARY KEY , "+ colDeptNombre+ " TEXT)");

bd.execSQL("CREATE TABLE "+tablaEmpleados+" ("+colID+" INTEGER

PRIMARY KEY AUTOINCREMENT, "+ colNombre+" TEXT, "+colEdad+"

Integer, "+colDept+" INTEGER NOT NULL ,FOREIGN KEY

("+colDept+") REFERENCES "+tablaDepartamentos+"

("+colDeptID+"));");

bd.execSQL("CREATE TRIGGER fk_empdept_deptid " +

" BEFORE INSERT "+" ON "+tablaEmpleados+

" FOR EACH ROW BEGIN"+ " SELECT CASE WHEN ((SELECT

"+colDeptID+" FROM "+tablaDepartamentos+" WHERE

"+colDeptID+"=new."+colDept+" ) IS NULL)"+

" THEN RAISE (ABORT,'Foreign Key Violation') END;"+

" END;");

bd.execSQL("CREATE VIEW "+vistaEmps+

" AS SELECT "+tablaEmpleados+"."+colID+" AS _id,"+

" "+tablaEmpleados+"."+colNombre+","+

" "+tablaEmpleados+"."+colEdad+","+

" "+tablaDepartamentos+"."+colDeptNombre+""+

" FROM "+tablaEmpleados+" JOIN "+tablaDepartamentos+

" ON "+tablaEmpleados+"."+colDept+"

="+tablaDepartamentos+"."+colDeptID);

insertarDepartamentos(bd);

}

El método crea las tablas con sus correspondientes campos, una vista y un trigger. El

método es invocado cuando se crea la base de datos, es decir, cuando la base de datos

no existe en el disco y se ejecuta sólo una vez en el mismo dispositivo: la primera vez

que la aplicación corre en dicho dispositivo.

Page 4: Ejemplo Base de Datos SQLite (Android)

Modificando el esquema de la base de datos.

A veces, necesitamos alterar el esquema de la base de datos, por ejemplo, añadiendo

nuevas tablas o cambiando los tipos de los campos. Esto se consigue sobrecargando el

método onUpdate(SQLiteDatabase db,int old Version,int newVerison:

@Override

public void onUpgrade(SQLiteDatabase bd, int viejaVersion,

int nuevaVersion)

{

bd.execSQL("DROP TABLE IF EXISTS "+tablaEmpleados);

bd.execSQL("DROP TABLE IF EXISTS "+tablaDepartamentos);

bd.execSQL("DROP TRIGGER IF EXISTS dept_id_trigger");

bd.execSQL("DROP TRIGGER IF EXISTS dept_id_trigger22");

bd.execSQL("DROP TRIGGER IF EXISTS fk_empdept_deptid");

bd.execSQL("DROP VIEW IF EXISTS "+vistaEmps);

onCreate(bd);

}

Este método es invocado cuando cambia el número de versión especificado en el

constructor de la clase.

Cuando desees incorporar un cambio en el esquema de la base de datos, tendrás que

cambiar el número de versión en el constructor de la clase. La implementación más

habitual, como en este caso, consiste en borrar (DROP) las tablas, vistas y triggers

creados con anterioridad para crearlos de nuevo.

Manejando claves externas (Foreign-Key)

Hemos mencionado anteriormente que SQLite 3, por defecto, no soporta restricciones

de clave externa. Sin embargo, podemos simular dichas restricciones mediante triggers

(un trigger -o disparador- es un procedimiento que se ejecuta cuando se cumple una

condición establecida al realizar una operación de inserción, actualización o borrado

sobre una base de datos).

Crearemos un trigger que garantice que cuando se inserta un nuevo empleado, el valor

de departamento está presente en la tabla TDepartamentos. La instrucción SQL para

crear un trigger de este tipo tiene el siguiente aspecto:

CREATE TRIGGER fk_empdept_deptid Before INSERT ON TEmpleados

FOR EACH ROW BEGIN

SELECT CASE WHEN ((SELECT idDept FROM TDepartamentos

WHERE idDept = new.departamento ) IS NULL)

THEN RAISE (ABORT,'Foreign Key Violation')

END;

END

Page 5: Ejemplo Base de Datos SQLite (Android)

Creamos este trigger en el método onCreate tal como sigue:

bd.execSQL("CREATE TRIGGER fk_empdept_deptid " +

" BEFORE INSERT "+" ON "+tablaEmpleados+

" FOR EACH ROW BEGIN"+ " SELECT CASE WHEN ((SELECT

"+colDeptID+" FROM "+tablaDepartamentos+" WHERE

"+colDeptID+"=new."+colDept+") IS NULL)"+

" THEN RAISE (ABORT,'Foreign Key Violation') END;"+

" END;");

Ejecutando sentencias SQL

Empecemos a ejecutar sentencias SQL básicas. Puedes ejecutar cualquier sentencia

SQL de manipulación de datos que no sea una consulta select, esto es, una operación

insert, delete, o update mediante una llamada a bd.execSQL(String

sentenciaSQL):

bd.execSQL("CREATE TABLE "+tablaDepartamentos+" ("+colDeptID+

" INTEGER PRIMARY KEY , "+ colDeptNombre+ " TEXT)");

Insertando nuevos registros

Para insertar nuevas filas en la tabla TDepartamentos usamos el siguiente código:

void insertarDepartamentos(SQLiteDatabase bd)

{

ContentValues cv=new ContentValues();

cv.put(colDeptID, 1);

cv.put(colDeptNombre, "Ventas");

bd.insert(tablaDepartamentos, colDeptID, cv);

cv.put(colDeptID, 2);

cv.put(colDeptNombre, "Contabilidad");

bd.insert(tablaDepartamentos, colDeptID, cv);

cv.put(colDeptID, 3);

cv.put(colDeptNombre, "Informática");

bd.insert(tablaDepartamentos, colDeptID, cv);

bd.insert(tablaDepartamentos, colDeptID, cv);

}

Observa que necesitamos invocar al método this.getWritableDatabase() para abrir

una conexión de lectura/escritura con la base de datos. La función

ContentValues.put() tiene dos parámetros: el nombre de la columna y el valor que

se le pasa.

Page 6: Ejemplo Base de Datos SQLite (Android)

Cambiando valores

Para ejecutar una sentencia update disponemos de dos métodos diferentes:

1. ejecutar bd.execSQL()

2. o invocar el método bd.update():

public int actualizarDatosEmpleado(Empleado emp)

{

SQLiteDatabase bd=this.getWritableDatabase();

ContentValues cv=new ContentValues();

cv.put(colNombre, emp.getNombre());

cv.put(colEdad, emp.getEdad());

cv.put(colDept, emp.getDept());

return bd.update(tablaEmpleados, cv, colID+"=?", new String

[]{String.valueOf(emp.getID())});

}

El método update tiene los siguientes parámetros:

1. String Table: la tabla que contien el registro que queremos modificar

2. ContentValues cv: el objeto de contenido que tiene los nuevos valores

3. String where clause: la cláusula WHERE para especificar qué registro

modificar.

4. String[] args: los argumetnos de la clásular WHERE

Eliminando registros

Como con update, para ejecutar una sentencia delete disponemos de dos métodos:

1. ejecutar bd.execSQL()

2. o invocar el método bd.delete():

public void eliminarEmpleado(Empleado emp)

{

SQLiteDatabase bd=this.getWritableDatabase();

bd.delete(tablaEmpleados,colID+"=?",

new String [] {String.valueOf(emp.getID())});

bd.close();

}

El método delete tiene los mismo parámetros que el método update.

Page 7: Ejemplo Base de Datos SQLite (Android)

Ejecutando consultas de selección

Para ejecutar consultas de selección podemos utilizar dos métodos:

1. ejecutar bd.rawQuery()

2. o invocar el método db.query()

Para ejecutar una consulta tipo raw para recoger todos los departamentos:

Cursor getTodosLosDepartamentos()

{

SQLiteDatabase bd=this.getReadableDatabase();

Cursor cur=bd.rawQuery("SELECT "+colDeptID+" as _id,

"+colDeptNombre+" from "+tablaDepartamentos,new String [] {});

return cur;

}

El método rawQuery tiene dos parámetros:

1. String query: la sentencia select

2. String[] selection args: los argumentos si el select incluye una cláusula WHERE

Notas

1. El resultado de una consulta se devuelve en un objeto de la clase Cursor.

2. En una sentencia select si la columna de la clave primaria (el campo id) tiene

un nombre distino a _id, entonces tienes que emplear un alias de la forma

SELECT [nombre campo] as _id. En otras palabras, el objeto Cursor espera

siempre que el campo de la clave primaria tenga como nombre _id, de lo

contrario, lanzará una excepción.

Otra forma de llevar a cabo una consulta de selección es usando el método

bd.query(). Una consulta para listar los empleados de un determinado departamento

a partir de una vista tendría el siguiente aspecto:

public Cursor getEmpleadoPorDept(String Dept)

{

SQLiteDatabase bd=this.getReadableDatabase();

String [] columns=new

String[]{"_id",colNombre,colEdad,colDeptNombre};

Cursor c = bd.query(vistaEmps, columns,

colDeptNombre+"=?", new String[]{Dept}, null, null, null);

return c;

}

El método bd.query() tiene los siguientes parámetros:

1. String Table Name: el nombre de la tabla sobre la que se ejecuta la consulta.

Page 8: Ejemplo Base de Datos SQLite (Android)

2. String [ ] columns: la proyección de la consulta, es decir, los campos que se

quieren consultar.

3. String WHERE clause: la cláusula where; si no hay, pasa el valor null

4. String [ ] selection args: los parámetros de la cláusula WHERE

5. String Group by: un string especificando la cláusula group by

6. String Having: un string especificando una cláusula HAVING

7. String Order By: un string especificando una cláusula Order By

Manejando cursores

Los resultados de las consultas se recogen en objetos de tipo Cursor. Existen algunos

métodos comunes que podrás utilizar con los cursores:

1. boolean moveToNext(): avanza el cursor una posición (siguiente registro) en

la tabla de resultados. Devuelve false si el movimiento supone ir más allá del

ultimo registro.

2. boolean moveToFirst(): retrocede el cursor hasta el primer registro del

conjunto de resultados. Devuelve false si el conjunto de resultados está vacío.

3. boolean moveToPosition(int position): desplaza el cursor a la posición de

un determinado registro. Devuelve false si la posición no es alcanzable.

4. boolean moveToPrevious(): mueve el cursor al registro anterior al actual en el

conjunto de resultados. Devuelve false si la posición va más allá de la pimera

fila.

5. boolean moveToLast(): mueve el cursor al ultimo registro del conjunto de

resultados. Devuelve false si el conjunto de resultados está vacío.

También existen métodos muy útiles para comprobar la posición actual de un cursor:

boolean isAfterLast(), isBeforeFirst, isFirst, isLast y

isNull(columnIndex). Por otra parte, si tienes un conjunto de resultados con un único

registro y necesitas acceder el valor de un determinado campo del mismo se puede

proceder de la siguiente manera:

public int getIDdepartamento(String Dept)

{

SQLiteDatabase bd=this.getReadableDatabase();

Cursor c=bd.query(tablaDepartamentos, new String[]{colDeptID+

" as _id",colDeptNombre},colDeptNombre+"=?", new

String[]{Dept}, null, null, null);

c.moveToFirst();

return c.getInt(c.getColumnIndex("_id"));

}

Tenemos Cursor.getColumnIndex(String ColumnName) para recuperar el índice de

un campo a partir de su nombre. Después, para obtener el valor de una determinada

columna, tenemos el método Cursor.getInt(int ColumnIndex).

Page 9: Ejemplo Base de Datos SQLite (Android)

Asimismo están los métodos getShort, getString, getDouble, y getBlob para

devolver los valores como un array de bytes. Es una buena práctica cerrar un cursor

después de haberlo usado mediante close().