Creacion y gestion de una base de datos SQLite

SQLite es un motor de base de datos relacional de código abierto y muy potente, eso hace que actualmente sea muy usado por los desarrolladores. Sus principales características son que precisa de poca configuración, no necesita ningún servidor ya que directamente lee y escribe en archivos de disco normales, ocupa muy poco tamaño en el almacenamiento y a parte es multiplataforma.

Android ofrece de serie soporte total para la creación y administración de base de datos SQLite a través del paquete “android.database.sqlite”. Solo tendremos que definir las sentencias SQL para crear y gestionar la base de datos. Iré explicando poco a poco y al final mostraré las clases íntegramente.

1. Creación base de datos SQLite
Para poder crear bases de datos en nuestra aplicación debemos usar las clases hijas de “SQLiteOpenHelper”. Que nos pide crear un constructor y sobreescribir dos métodos:

“onCreate(SQLiteDatabase db)”

“onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)”

El primero se encargara de crear las tablas si no existen y el segundo las actualizara si nos es necesario (imaginemos que creamos una tabla con 2 columnas y mas adelante nos hace falta añadir mas columnas, con este método podríamos hacerlo pasándole como parámetro la versión de la tabla antigua y la versión de la nueva tabla).
Dentro de una base de datos podemos crear tantas tablas como nos sea necesario, su estructura y la que usaremos en el ejemplo tendrá la siguiente forma:
id nombre telefono email
1 Pedro 111111111 pedro@DB.cu
2 Sandra 111111111 sandra@DB.cu
3 Maria 111111111 maria@DB.cu
4 Daniel 111111111 daniel@DB.cu
Así que vamos a verlo en un ejemplo:
public class MiBaseDatos extends SQLiteOpenHelper {
 
    private static final int VERSION_BASEDATOS = 1;

    // Nombre de nuestro archivo de base de datos
    private static final String NOMBRE_BASEDATOS = "mibasedatos.db";
    
    // Sentencia SQL para la creación de una tabla
    private static final String TABLA_CONTACTOS = "CREATE TABLE contactos" +  
            "(_id INT PRIMARY KEY, nombre TEXT, telefono INT, email TEXT)";


    // CONSTRUCTOR de la clase
    public MiBaseDatos(Context context) {
        super(context, NOMBRE_BASEDATOS, null, VERSION_BASEDATOS);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(TABLA_CONTACTOS);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLA_CONTACTOS);
        onCreate(db);
    }
}

Como vemos en el ejemplo, en muy pocas lineas de código podemos crear una tabla en nuestro archivo de base de datos.

Lo primero que hacemos es crear tres variables:

NOMBRE_BASEDATOS: sera el nombre de nuestro archivo de base de datos

VERSION_BASEDATOS: la versión de nuestra base de datos

TABLA_CONTACTOS: un string que contiene una sentencia SQL para la creación de una tabla llamada contactos. Lo que tenemos en parentesis son las columnas, un índice INT primario (no es obligatorio pero si muy recomendable para no tener problemas a la hora de insertar, modificar o borrar alguna fila ya que es un valor único), un nombre TEXT, un telefono INT y un e-mail TEXT. Como podemos ver hay que especificar que tipo de datos va a manejar esa columna (TEXT, NUM, INT, REAL, …)

La sintaxis SQL es muy extensa y aquí nos vamos a centrar en lo justo y necesario si deseas conocer mas sobre ella te recomiendo que visites tu pagina web SQLite.

Seguimos con el constructor de la clase que nos pide como parámetros un context, el nombre del archivo de la base de datos, un CursorFactory que no lo vamos a necesitar y por lo tanto lo ponemos a null y la versión de nuestra base de datos.

Comentar que para gestionar la base de datos y la clase que estamos creando, vamos a usar métodos de la clase “SQLiteDatabase”.

Y para terminar la clase sobreescribimos los métodos onCreate y onUprade usando el método “execSQL()” que nos pide como parametro una unica sentencia SQL que no sea un SELECT o cualquier otra sentencia que devuelva datos. Entonces en el onCreate simplemente creamos la tabla si no existe y en el onUpgrade borramos la tabla si existe y creamos una nueva.

2. Gestionar base de datos
Para gestionar la base de datos vamos a crear unos métodos personalizados para leer, escribir, modificar y eliminar registros de nuestra tabla. Aunque también podríamos usar sentencias SQL con el método execSQL, pero este no va a ser el caso.
2.1 Insertar registros
public void insertarCONTACTO(int id, String nom, int tlf, String email) {
    SQLiteDatabase db = getWritableDatabase();
    if(db != null){
        ContentValues valores = new ContentValues();
        valores.put("_id", id);
        valores.put("nombre", nom);
        valores.put("telefono", tlf);
        valores.put("email", email);
        db.insert("contactos", null, valores);
        db.close();   
    }
}

Creamos un método “insertarCONTACTO” y como parámetros los datos que queremos insertar en la tabla (id, nombre, telefono, email). Dentro del método creamos una instancia de la clase “SQLiteDatabase” y usamos su método “getWritableDatabase()” para poder escribir en la base de datos. Encapsulamos todo en un if por si acaso la base de datos no existe y ya dentro del if creamos una instancia de la clase “ContentValues” que como su nombre indica es un almacenador de un conjunto de datos. Usamos el metodo “put(key, value)” que nos pide como primer parámetro “key” el nombre donde establecer el valor almacenado y como segundo parámetro el valor que queremos almacenar. Una vez almacenamos los datos insertamos una fila en la tabla usamos el método “insert(table, nullColumnHack, values)” que nos pide el nombre de la tabla “table”, un segundo parámetro en caso de que necesitemos insertar valores nulos en la tabla “nullColumnHack” en este caso lo dejaremos pasar ya que no lo vamos a usar y por lo tanto lo ponemos a null y como tercer parámetro “values” nos pide un ContentValues. Para concluir deberemos cerrar la base de datos con el método “close()”.

2.2 Modificar registros
public void modificarCONTACTO(int id, String nom, int tlf, String email){
    SQLiteDatabase db = getWritableDatabase();
    ContentValues valores = new ContentValues();
    valores.put("_id", id);
    valores.put("nombre", nom);
    valores.put("telefono", tlf);
    valores.put("email", email);
    db.update("contactos", valores, "_id=" + id, null);
    db.close();   
}

Prácticamente es igual que el anterior método pero con la excepción de que aquí estamos usando el método “update(table, values, whereClause, whereArgs)” para actualizar/modificar registros de nuestra tabla. Este método nos pide el nombre de la tabla “table”, los valores a modificar/actualizar “values” (ContentValues), una condición WHERE “whereClause” que nos sirve para indicarle que valor queremos que actualicé (en este caso cogemos como referencia la id de nuestro contacto) y como ultimo parámetro “whereArgs” podemos pasarle los valores nuevos a insertar, en este caso no lo vamos a necesitar por lo tanto lo ponemos a null. Para terminar deberemos cerrar siempre nuestra base de datos con el método “close()”.

2.3 Borrar registros
public void borrarCONTACTO(int id) {
    SQLiteDatabase db = getWritableDatabase();
    db.delete("contactos", "_id="+id, null);
    db.close();  
}

Para borrar registros usaremos el método “delete(table, whereClause, whereArgs)” que nos pide el nombre de la tabla “table”, el registro a borrar “whereClause” que tomaremos como referencia su id y como ultimo parámetro “whereArgs” los valores a borrar.

2.4 Leer registros
Para leer registros vamos a crear una clase “Contactos” con un constructor y varios métodos get/set para convertir una fila de la tabla en un objeto y nos sea mas fácil acceder a cualquier valor de ese registro. Los métodos get/set simplemente son métodos para recuperar o establecer un valor del objeto Contactos.

public class Contactos {

    private int id;
    private String nombre;
    private int telefono;
    private String email;
 
    // Constructor de un objeto Contactos
    public Contactos(int id, String nombre, int telefono, String email) {
        this.id = id;
        this.nombre = nombre;
        this.telefono = telefono;
        this.email = email;
    }
 
    // Recuperar/establecer ID
    public int getID() {
        return id;
    }
    public void setID(int id) {
        this.id = id;
    }
 
    // Recuperar/establecer NOMBRE
    public String getNOMBRE() {
        return nombre;
    }
    public void setNOMBRE(String nombre) {
        this.nombre = nombre;
    }
 
    // Recuperar/establecer TELEFONO
    public int getTELEFONO() {
        return telefono;
    }
    public void setTELEFONO(int telefono) {
        this.telefono = telefono;
    }
 
    // Recuperar/establecer EMAIL
    public String getEMAIL() {
        return email;
    }
    public void setEMAIL(String email) {
        this.email = email;
    }
}

Una vez creada nuestra clase Contactos volvemos a la clase “MiBaseDatos” para crear los métodos de lectura de un registro y lectura de todos los registros de la tabla.

2.4.1 Leer un registro
Para realizar consultas a la base de datos podremos utilizar cualquiera de estos dos métodos:

  • query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit) – Método que usaremos en el ejemplo, como se puede observar recibe muchos parametros que son utilizados para crear la declaración SQL.
  • rawquery(sql, selectionArgs) – Este método es mucho mas simple que el anterior, directamente recibe una declaración SQL como primer parámetro y un segundo parámetro opcional (Recomendado para los que tengan experiencia en lenguaje SQL, ¡ Gracias al usuario por el comentario !)

Los dos métodos expuestos nos devolverán un Cursor que podremos recorrer para recuperar todos los registros de la base de datos. Vamos a continuar con el atículo y vamos a crear el método para recuperar un registro:

public Contactos recuperarCONTACTO(int id) {
    SQLiteDatabase db = getReadableDatabase();
    String[] valores_recuperar = {"_id", "nombre", "telefono", "email"};
    Cursor c = db.query("contactos", valores_recuperar, "_id=" + id, 
            null, null, null, null, null);
    if(c != null) {
        c.moveToFirst();
    }
    Contactos contactos = new Contactos(c.getInt(0), c.getString(1), 
            c.getInt(2), c.getString(3));
    db.close();
    c.close();
    return contactos;
}

Este método devuelve un objeto Contactos con los datos del contacto (id, nombre, telefono, email). En este caso como queremos leer hacemos uso del método “getReadableDatabase()”. Creamos una variable “valores_recuperar” con las columnas que queremos recuperar, en este caso vamos a recuperar todos los datos de un registro. Continuamos creando un “Cursor” que se encarga de devolver el resultado de un registro de la tabla y lo almacena en la memoria, le aplicamos el método:

query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit)

Con este método conseguimos leer un registro de la tabla. Como primer parámetro “table” nos pide el nombre de la tabla , “columns” las columnas que queremos recuperar, con “selection” le indicamos el registro a recuperar (en este caso recuperamos con el id), o los registros a recuperar “selectionArgs”, “groupBy” para agrupar los registros consultados , “having” es un filtro para incluir los registros en el cursor (este parámetro se usaría con groupBy), “orderBy” para ordenar las filas y “limit” para limitar el numero de filas consultadas.

Con el método “moveToFirst()” ponemos el cursor al inicio de los datos almacenados. Lo encapsulamos en un if por si acaso no hay datos almacenados.

Continuamos creando un objeto “Contactos” para almacenar los datos consultados de un registro, y los vamos recuperando del cursor con métodos get indicando la posición de la columna.

Para terminar debemos cerrar la base de datos y el cursor.

2.4.2 Leer todos los registro
    public List<Contactos> recuperarCONTACTOS() {
        SQLiteDatabase db = getReadableDatabase();
        List<Contactos> lista_contactos = new ArrayList<Contactos>();
        String[] valores_recuperar = {"_id", "nombre", "telefono", "email"};
        Cursor c = db.query("contactos", valores_recuperar, 
                null, null, null, null, null, null);
        c.moveToFirst();
        do {
            Contactos contactos = new Contactos(c.getInt(0), c.getString(1), 
                    c.getInt(2), c.getString(3));
            lista_contactos.add(contactos);
        } while (c.moveToNext());
        db.close();
        c.close();
        return lista_contactos;
    }

El método que usamos en este casp es muy similar al de leer un registro pero en este caso no especificamos que registro queremos recuperar, por lo tanto ponemos su parámetro a null. A parte creamos una variable “lista_contactos” donde almacenaremos todos los registros de la tabla en objetos contactos. En el bucle do-while usamos el método “moveToNext()” como parámetro que se encargara de pasar al siguiente registro de la tabla y por lo tanto recorrer todos los registros de la tabla.

3. Uso de nuestra base de datos en una Activity
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        MiBaseDatos MDB = new MiBaseDatos(getApplicationContext());
        
        // Escribimos 4 registros en nuestra tabla
        MDB.insertarCONTACTO(1, "Pedro", 111111111, "pedro@DB.es");
        MDB.insertarCONTACTO(2, "Sandra", 222222222, "sandra@DB.es");
        MDB.insertarCONTACTO(3, "Maria", 333333333, "maria@DB.es");
        MDB.insertarCONTACTO(4, "Daniel", 444444444, "daniel@DB.es");
        
        // Recuperamos los 4 registros y los mostramos en el log
        Log.d("TOTAL", Integer.toString(MDB.recuperarCONTACTOS().size()));
        int[] ids = new int[MDB.recuperarCONTACTOS().size()];
        String[] noms = new String[MDB.recuperarCONTACTOS().size()];
        int[] tlfs = new int[MDB.recuperarCONTACTOS().size()];
        String[] emls = new String[MDB.recuperarCONTACTOS().size()];
        for (int i = 0; i < MDB.recuperarCONTACTOS().size(); i++) {
            ids[i] = MDB.recuperarCONTACTOS().get(i).getID();
            noms[i] = MDB.recuperarCONTACTOS().get(i).getNOMBRE();
            tlfs[i] = MDB.recuperarCONTACTOS().get(i).getTELEFONO();
            emls[i] = MDB.recuperarCONTACTOS().get(i).getEMAIL();
            Log.d(""+ids[i], noms[i] + ", " + tlfs[i] + ", " + emls[i]);
        }
        
        // Modificamos el registro 3
        MDB.modificarCONTACTO(3, "PPPPP", 121212121, "xxxx@xxxx.es");
        
        // Recuperamos el 3 registro y lo mostramos en el log
        int id = MDB.recuperarCONTACTO(3).getID();
        String nombre = MDB.recuperarCONTACTO(3).getNOMBRE();
        int telefono = MDB.recuperarCONTACTO(3).getTELEFONO();
        String email = MDB.recuperarCONTACTO(3).getEMAIL();
        Log.d(""+id, nombre + ", " + telefono + ", " + email);
        
        // Borramos el registro 3
        MDB.borrarCONTACTO(3); 
    }
}

Lo primero que hacemos es crear una instancia de nuestra clase “MiBaseDatos” pasándole como parámetro un contexto.

Para insertar registros llamamos al método “insertarCONTACTO(id, nom, tlf, email)” y simplemente le indicamos los valores a insertar.

A la hora de recuperar registros hacemos uso del método “MDB.recuperarCONTACTOS.size()” que nos devuelve el numero de registros de la tabla, sabiendo esto podemos crear 4 arrays con ese tamaño para almacenar los datos separados por categoría. Con el método “get(i)” recuperamos un registro de la tabla y después con los métodos “getID()”, “getNOMBRE()”, “getTELEFONO()” y “getEMAIL()” vamos recuperando los datos de ese registro. Para terminar mostramos todo en el log.

Podemos modificar un registro de nuestra tabla con el método “modificarCONTACTO(id, nom, tlf, email)”. Como primer parámetro indicaremos el registro a modificar y los siguientes parámetros serán los nuevos valores para ese registro. Mostramos el nuevo registro en el log.

Para concluir podemos borrar registros de la tabla con el método “borrarCONTACTO(id)” que nos pide como parámetro la id del registro a borrar.

Resúmen
Proyecto MisContactos
clase Contactos.java
clase MiBaseDatos.java
clase MainActivity.java
activity_main.xls
En esta última irían los componentes visuales, en esta entrada no hacemos referencia a ellos, pero en próximas entradas haremos algo más funcional, estoy trabajando en ello…
clase Contactos.java
package com.example.miscontactos;

public class Contactos {

private int id;
private String nombre;
private int telefono;
private String email;

// Constructor de un objeto Contactos
public Contactos(int id, String nombre, int telefono, String email) {
this.id = id;
this.nombre = nombre;
this.telefono = telefono;
this.email = email;
}

// Recuperar/establecer ID
public int getID() {
return id;
}
public void setID(int id) {
this.id = id;
}

// Recuperar/establecer NOMBRE
public String getNOMBRE() {
return nombre;
}
public void setNOMBRE(String nombre) {
this.nombre = nombre;
}

// Recuperar/establecer TELEFONO
public int getTELEFONO() {
return telefono;
}
public void setTELEFONO(int telefono) {
this.telefono = telefono;
}

// Recuperar/establecer EMAIL
public String getEMAIL() {
return email;
}
public void setEMAIL(String email) {
this.email = email;
}
}

clase MiBaseDatos.java
package com.example.miscontactos;

import java.util.ArrayList;
import java.util.List;

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

public class MiBaseDatos extends SQLiteOpenHelper {

private static final int VERSION_BASEDATOS = 1;

// Nombre de nuestro archivo de base de datos
private static final String NOMBRE_BASEDATOS = “mibasedatos.db”;

// Sentencia SQL para la creación de una tabla
private static final String TABLA_CONTACTOS = “CREATE TABLE contactos” +
“(_id INT PRIMARY KEY, nombre TEXT, telefono INT, email TEXT)”;

// CONSTRUCTOR de la clase
public MiBaseDatos(Context context) {
super(context, NOMBRE_BASEDATOS, null, VERSION_BASEDATOS);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(TABLA_CONTACTOS);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(“DROP TABLE IF EXISTS ” + TABLA_CONTACTOS);
onCreate(db);
}

public void insertarCONTACTO(int id, String nom, int tlf, String email) {
SQLiteDatabase db = getWritableDatabase();
if(db != null){
ContentValues valores = new ContentValues();
valores.put(“_id”, id);
valores.put(“nombre”, nom);
valores.put(“telefono”, tlf);
valores.put(“email”, email);
db.insert(“contactos”, null, valores);
db.close();
}
}

public void modificarCONTACTO(int id, String nom, int tlf, String email){
SQLiteDatabase db = getWritableDatabase();
ContentValues valores = new ContentValues();
valores.put(“_id”, id);
valores.put(“nombre”, nom);
valores.put(“telefono”, tlf);
valores.put(“email”, email);
db.update(“contactos”, valores, “_id=” + id, null);
db.close();
}

public void borrarCONTACTO(int id) {
SQLiteDatabase db = getWritableDatabase();
db.delete(“contactos”, “_id=”+id, null);
db.close();
}

public Contactos recuperarCONTACTO(int id) {
SQLiteDatabase db = getReadableDatabase();
String[] valores_recuperar = {“_id”, “nombre”, “telefono”, “email”};
Cursor c = db.query(“contactos”, valores_recuperar, “_id=” + id,
null, null, null, null, null);
if(c != null) {
c.moveToFirst();
}
Contactos contactos = new Contactos(c.getInt(0), c.getString(1),
c.getInt(2), c.getString(3));
db.close();
c.close();
return contactos;
}

public List<Contactos> recuperarCONTACTOS() {
SQLiteDatabase db = getReadableDatabase();
List<Contactos> lista_contactos = new ArrayList<Contactos>();
String[] valores_recuperar = {“_id”, “nombre”, “telefono”, “email”};
Cursor c = db.query(“contactos”, valores_recuperar,
null, null, null, null, null, null);
c.moveToFirst();
do {
Contactos contactos = new Contactos(c.getInt(0), c.getString(1),
c.getInt(2), c.getString(3));
lista_contactos.add(contactos);
} while (c.moveToNext());
db.close();
c.close();
return lista_contactos;
}

}

clase MainActivity.java
package com.example.miscontactos;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

MiBaseDatos MDB = new MiBaseDatos(getApplicationContext());

// Escribimos 4 registros en nuestra tabla
MDB.insertarCONTACTO(1, “Pedro”, 111111111, “pedro@DB.es”);
MDB.insertarCONTACTO(2, “Sandra”, 222222222, “sandra@DB.es”);
MDB.insertarCONTACTO(3, “Maria”, 333333333, “maria@DB.es”);
MDB.insertarCONTACTO(4, “Daniel”, 444444444, “daniel@DB.es”);

// Recuperamos los 4 registros y los mostramos en el log
Log.d(“TOTAL”, Integer.toString(MDB.recuperarCONTACTOS().size()));
int[] ids = new int[MDB.recuperarCONTACTOS().size()];
String[] noms = new String[MDB.recuperarCONTACTOS().size()];
int[] tlfs = new int[MDB.recuperarCONTACTOS().size()];
String[] emls = new String[MDB.recuperarCONTACTOS().size()];
for (int i = 0; i < MDB.recuperarCONTACTOS().size(); i++) {
ids[i] = MDB.recuperarCONTACTOS().get(i).getID();
noms[i] = MDB.recuperarCONTACTOS().get(i).getNOMBRE();
tlfs[i] = MDB.recuperarCONTACTOS().get(i).getTELEFONO();
emls[i] = MDB.recuperarCONTACTOS().get(i).getEMAIL();
Log.d(“”+ids[i], noms[i] + “, ” + tlfs[i] + “, ” + emls[i]);
}

// Modificamos el registro 3
MDB.modificarCONTACTO(3, “PPPPP”, 121212121, “xxxx@xxxx.es”);

// Recuperamos el 3 registro y lo mostramos en el log
int id = MDB.recuperarCONTACTO(3).getID();
String nombre = MDB.recuperarCONTACTO(3).getNOMBRE();
int telefono = MDB.recuperarCONTACTO(3).getTELEFONO();
String email = MDB.recuperarCONTACTO(3).getEMAIL();
Log.d(“”+id, nombre + “, ” + telefono + “, ” + email);

// Borramos el registro 3
MDB.borrarCONTACTO(3);

}

}

2 thoughts on “Creacion y gestion de una base de datos SQLite

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *