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.

En este caso nos vamos a centrar en: 
Creacion y gestion de una base de datos SQLite
Copia base de datos existente a nuestra aplicacion 



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.es
2 Sandra 111111111 sandra@DB.es
3 Maria 111111111 maria@DB.es
4 Daniel 111111111 daniel@DB.es


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.



CODIGO DE EJEMPLO: DESCARGAR




4. Copiar base de datos existente

En ocasiones será necesario incluir a nuestro proyecto un archivo de base de datos ya creado. O podriamos crearlo nosotros mismos con cualquiera de estos dos gestores de bases de datos:
SQLite Database Browser (Gratuita, multiplataforma y de código abierto)
Valentina estudio (Aplicación multiplataforma recomendada en los comentarios)
En este caso incluiremos el archivo de base de datos en la carpeta assets de nuestro proyecto. Y por ejemplo crear un método personalizado en nuestra Activity principal y copiar la base de datos de la carpeta assets a la carpeta privada de base de datos de nuestra aplicación. A continuación dejo un ejemplo:
    private void copiarBaseDatos() {
        String ruta = "/data/data/com.example.sqlite/databases/";
        String archivo = "contactos.db";
        File archivoDB = new File(ruta + archivo);
        if (!archivoDB.exists()) {
        try {
            InputStream IS = getApplicationContext().getAssets().open(archivo);
            OutputStream OS = new FileOutputStream(archivoDB);
            byte[] buffer = new byte[1024];
            int length = 0;
            while ((length = IS.read(buffer))>0){
                OS.write(buffer, 0, length);
            }
            OS.flush();
            OS.close();
            IS.close();
        } catch (FileNotFoundException e) {
            Log.e("ERROR", "Archivo no encontrado, " + e.toString());
        } catch (IOException e) {
            Log.e("ERROR", "Error al copiar la Base de Datos, " + e.toString());
        }
    }
No me voy a parar a explicar esto ya que tenemos en este mismo blog un articulo que trata sobre como manejar los archivos. Simplemente comentar que usaríamos el método al comienzo del onCreate para tener disponible la base de datos desde el primer comienzo de la aplicación, a parte comentar que en la ruta "/data/data/'NOMBREdelPAQUETE'/databases" se encuentran nuestros archivos de base de datos. Para mas información sobre manejar archivos visitar: Opciones de almacenamiento.

76 comentarios:

  1. genial!! me ha ayudado un montón gracias

    ResponderEliminar
    Respuestas
    1. El Baul De Android: Base De Datos Sqlite >>>>> Download Now

      >>>>> Download Full

      El Baul De Android: Base De Datos Sqlite >>>>> Download LINK

      >>>>> Download Now

      El Baul De Android: Base De Datos Sqlite >>>>> Download Full

      >>>>> Download LINK y3

      Eliminar
  2. Muchas gracias. El punto 4 me ha aclarado mucho las ideas.
    Para los que tengais algo de experiencia con el lenguaje SQL, os recomiendo utilizar el método rawquery en vez de query, ya que te permite insertar la sentencia SQL tal cual.
    Un saludo.

    ResponderEliminar
    Respuestas
    1. Gracias por la anotación, porque en el artículo no lo tengo comentado. Haber si le hecho un ojo un día y lo explico un poco
      Un saludo !!

      Eliminar
    2. Muchas gracias, el raw query me sirvió bastante

      Eliminar
  3. Gracias por la aplicacion, la proxima vez la tendre en cuenta. La dejo comentada en el articulo por si le sirve a alguno

    ResponderEliminar
  4. Hola, enhorabuena por el tutorial. He creado una lista expandible utilizando estos mismos métodos en la base de datos. El problema surge cuando quiero añadir un item a un grupo ya existente, habiendo seleccionado previamente éste en un Spinner. La base de datos consta de dos tablas: una para los grupos y otra para los hijos. También he creado los métodos insertar, eliminar, actualizar y obtener en ambos casos. ¿Debo crear algún método nuevo para poder añadir un elemento a un grupo ya creado? ¿Cuál es la solución? Gracias, es urgente.

    ResponderEliminar
    Respuestas
    1. Gracias y perdona por tardar en contestar pero es que llevo un mes muy liado.

      No se realmente lo que estas haciendo pero teniendo la base de este tutorial puedes crear los métodos que te sean necesarios para añadir elementos a una tabla, eso ya depende de tus necesidades. Deberías crear un método que inserte elementos en la tabla dependiendo del grupo seleccionado, para luego poder recuperarlos según su grupo.

      Eliminar
  5. tengo un problema con mi base, tiene 5 tablas.... lo q pasa esq no se si se crea mi base, y bueno cuando quiero hacer un select a sin haber insertado ningun dato aun, me da un error "no such table"; pareciera como q no existe la tabla... xq si fuera por q no tiene datos me imagino q simplemente me devolveria un cursor vacio... ayudaaaaaa...!!!!

    ResponderEliminar
    Respuestas
    1. Debes utilizar el constructor de la base de datos en tu codigo android para que te cree la base de datos.

      Eliminar
  6. Gracias! Es todo muy claro y funcional, pero tengo un problema. En cualquiera de los métodos dentro de la clase que hereda de SQLiteOpenHelper que utilizo la sentencia: SQLiteDatabase db = getReadableDatabase(); lanza una SQLiteException. Alguien sabe porqué me pasa? (cabe aclarar que soy nuevo en la programación Android).

    ResponderEliminar
    Respuestas
    1. El error era mío (como era de esperarse). Tenía una base de datos con una versión más grande que la que había declarado. Saludos!

      Eliminar
  7. como consulto la fecha actual en sqlite xq en sql seria algo como esto select getdate() y listo.... pero en sqlite no funciona

    ResponderEliminar
    Respuestas
    1. Consulta directamente la fecha actual a Android. En google tendras mil ejemplos

      Eliminar
    2. https://www.youtube.com/user/anderwelt23

      La fecha actual en sqlite, puede ser consultada dentro de la misma base de datos sqlite de la siguiente manera: date('now'). Saludos!!

      Eliminar
  8. tengo una tabla con 4 campos y hasta ahi todo bien guardo y leo los datos sin problema, pero cuando le quiero agregar una columna al momento de leer los datos ya no lo hace y me manda error y ya no me abra la activity, y lo extraño es que cuando guardo datos me dice que los guardo correctamente, el problema es al leerlos. Espero alguien me pueda ayudar. Gracias!!!!

    ResponderEliminar
    Respuestas
    1. Lo unico que te puedo decir es que observes bien el Logcat ya que te informara porque se produce el error y a traves de esa informacion podras corregir la excepcion. Si tienes problemas copia el error por aqui haber si te puedo ayudar

      Eliminar
    2. Esto es lo que me pone en el logcat, espero que con esta informacion me puedas ayudar u orientar en lo que puede ser, ya que apenas estoy aprendiendo esta plataforma. Gracias!!!!

      Caused by: android.database.sqlite.SQLiteException: no such solumn: Titular while compiling: Select _id, Dependencia,Horario, Requisitos, Titular from Tramites
      at android.database.sqlite.SQLiteProgram.native_compile(Native Method)
      at android.database.sqlite.SQLiteProgram.compile(SQLiteProgram.java:110)
      at android.database.sqlite.SQLiteProgram.(SQLiteProgram.java:59)
      at android.database.sqlite.SQLiteQuery.(SQLiteQuery.java:49)
      .....

      Eliminar
    3. Ahi simplemente te indica que no existe la columna Titular. Debes comprobar que se crea y se recupera bien la columna, algo debes tener mal en el codigo

      Eliminar
  9. Hola, oye me surgió una duda con respecto al tutorial, ¿cada tema lo estas haciendo en una nueva clase?

    ResponderEliminar
    Respuestas
    1. Perdóname pero no entiendo muy bien lo que quieres preguntar, podrías explicar a que temas te refieres y que clases

      Eliminar
    2. Osea, que si cada tema que estas haciendo (creación de la base de datos,, insertar datos) los hiciste cada uno en una nueva clase o todos van en una sola, o de no ser así, donde los escribiste??

      Eliminar
    3. Si te descargas el codigo fuente que esta al final del punto 3 veras como esta estructurado todo. Hay 3 clases, la activity del punto 3, la clase objeto del punto 2.4 y el resto es la clase de base de datos del punto 1.

      Eliminar
  10. Excelente tuto, me ayudo a entender lo de las bases de datos, un pregunta, puedo hacer muchos inserts con una sola linea, me explico; en mysql tu puedes hacer un insert on tabla (valorA1,valorB1,valorC1),(valorA2,valorB2,valorC2),....,(valorAn,valorBn,valorCn); puedo hacer eso en sqlite??

    ResponderEliminar
    Respuestas
    1. Gracias por el comentario !! Si miras bien el tutorial en el punto 2.4.1 te dice que puedes utilizar 2 metodos para trabajar con la sqlite. En tu caso imagino que te refieres a trabajar con sentencias SQL, entonces deberias utilizar el metodo rawquery pasandole como argumento la sentencia "Insert into ....."

      Eliminar
  11. cargo la aplicacion en mi android y sale en la pantalla (Hello world!)
    Alguien me puede ayudar. Supongo que hay que hacer algo antes.

    ResponderEliminar
    Respuestas
    1. La aplicación no tiene ninguna interface de usuario, es normal que solo te ocurra eso. Observa la salida del logcat porque muestra la lectura de la base de datos creada en el ejemplo.

      Eliminar
    2. podrias ayudarme como hacer para mostrarla tabla de este ejemplo??, me seria de gran ayuda no logro hacerlo

      Eliminar
  12. Hola
    Podias explicarme como puedo hacer un select con el metodo rawquery en el que en la clausula select me compare con una variable de java
    Ej select * from tabla where columna = variable java

    Gracias

    ResponderEliminar
    Respuestas
    1. No he llegado a utilizar ese método pero puedes probar a crear un string con la consulta:

      String consulta = "select * from tabla...";

      Y aplicar ese string al método rawquery:

      db.rawquery(consulta, null);

      Eliminar
  13. Te luciste! gracias por la info, me ayudaste en mucho

    ResponderEliminar
  14. Hola Luis, necesito implementar la modificacion en una app, pero me manda error, te pongo el codigo

    public long GuardarModi(String [] servicio,String de, String ho, String re, String ti, String doc, String cos, String tiem, String vi, String dom, String tel, String fa, String co, String tra) {
    // TODO Auto-generated method stub
    ContentValues cv=new ContentValues();
    cv.put(dependencia,de);
    cv.put(horario,ho);
    cv.put(requisitos, re);
    cv.put(titular, ti);
    cv.put(documento, doc);
    cv.put(costo,cos);
    cv.put(tiempo,tiem);
    cv.put(vigencia,vi);
    cv.put(domicilio,dom);
    cv.put(telefono, tel);
    cv.put(fax, fa);
    cv.put(correo, co);
    cv.put(tramite, tra);

    //return nBD.rawquery("Update ");
    //servicio=new String [] {"2"};
    return nBD.update(N_TABLA,cv,"_id="+ servicio,null);
    }

    tambien puse el updete de la siguiente manera
    return nBD.update(N_TABLA,cv,"_id=?", servicio);

    pero de las dos formas me manda el siguiente error

    java.lang.nullpointerexception

    Espero me puedas ayudar, ya que llevo mucho tiempo atorada con este problema. Saludos.

    ResponderEliminar
    Respuestas
    1. Doy por hecho que quieres actualizar un registro de la tabla por lo que seria conveniente que revisaras el punto 2.2 del articulo. En principio los dos updates parecen correctos a si que el error debe venirte de otro sitio, revisa bien el logcat porque te dice exactamente donde esta el error en que clase java y la linea. Ese error es tipico por ejemplo cuando un objeto, variable, .. es nulo en ese momento de la ejecucion.

      Eliminar
    2. ya lo resolví, me faltaba abrir la conexión, gracias!!!!

      Eliminar
  15. gracias, por la labor.

    ResponderEliminar
  16. Hey ¿qué tal? Oye, de casualidad no sabes como podría manejar imágenes en las bases de datos? D: de verdad que me serviría y mucho...

    ResponderEliminar
    Respuestas
    1. Tienes dos opciones para almacenar una imagen en una columna de la base de datos:

      1.- Almacenar la ruta de la imagen en un String
      2.- O almacenar la imagen en forma de BLOB

      He estado probando la segunda por curiosidad y un blob simplemente en un array de bytes. Entonces la cuestion es convertir la imagen a un array de bytes y ya podrias almacenarla en una columna de la sqlite. Para recuperar la imagen seria el proceso inverso, convertir el array de bytes en un bitmap.


      He visto un par de metodos por google que te pueden servir:

      public static byte[] getBytes(Bitmap bitmap) {
      ByteArrayOutputStream stream = new ByteArrayOutputStream();
      bitmap.compress(CompressFormat.PNG, 0, stream);
      return stream.toByteArray();
      }

      public static Bitmap getImage(byte[] image) {
      return BitmapFactory.decodeByteArray(image, 0, image.length);
      }


      PD: haber cuando tenga algo de tiempo y editare el articulo ya que me gustaria mejorarlo un poco por ser el mas visitado el blog.

      Eliminar
    2. Hola Luis, gracias por hacernos tanto caso y por el blog.
      Yo estoy liado con las imagenes también, la BBDD funciona bien hasta que intento meter las fotos. Te resumo lo que he hecho:

      --------------------------------
      CONTACTOS.java:
      Añadir el campo "byte[] foto" para el constructor, al igual que tu con los otros campos.
      Añadidos metodos set&get de la fotos también con byte[]
      ----------------------------
      MiBaseDatos.java:
      Añadido "foto BLOB" en el CREATE TABLE
      Añadido en insertar, modificar: "valores.put("foto", foto);" pasandole byte[]
      Añadido en recuperar(int id) y List recuperar() en valores_recuperar: ,"foto"

      El problema lo tengo cuando ejecuta la linea:
      Cursor c = db.query("lobos", valores_recuperar, null, null, null, null, null, null);
      Directamente se detiene la aplicación y no me indica ningun error ni nada :(

      y en esta linea siguiente también añadí:
      "Contactos contactos= new Contactos(c.getInt(0), c.getString(1), c.getInt(2), c.getString(3), c.getBlob(4));"
      -------------------------------------------------
      Main.java:

      He introducido 4 contactos:
      db.insertarANIMAL(1, "Pedro", 111111111, "pedro@DB.es",null);
      db.insertarANIMAL(2, "Sandra", 222222222, "sandra@DB.es",null);
      db.insertarANIMAL(3, "Maria", 333333333, "maria@DB.es",null);
      db.insertarANIMAL(4, "Sonia", 444444444, "sonia@DB.es",null);

      Y transformo la imagen en bytes:
      foto = BitmapFactory.decodeResource(getResources(), R.drawable.nopicture);
      // convert bitmap to byte
      ByteArrayOutputStream stream = new ByteArrayOutputStream();
      foto.compress(Bitmap.CompressFormat.JPEG, 100, stream);
      byte imageInByte[] = stream.toByteArray();

      En principio todo eso lo hace bien.

      alguna idea donde está el fallo ?

      Eliminar
    3. He reducido la busqueda de mi error, en la parte de RecogerContactos (todos) tengo:
      String[] valores_recuperar = {"_id", "nombre", "telefono", "email", "foto"};

      Cursor c = db.query("lobos", valores_recuperar, null, null, null, null, null, null);
      c.moveToFirst();
      do {
      ALobos contactos = new ALobos();
      contactos.setID(c.getInt(0));
      contactos.setNOMBRE(c.getString(1));
      contactos.setTELEFONO(c.getInt(2));
      contactos.setEMAIL(c.getString(3));

      contactos.setFOTO(c.getBlob(4)); <----------------------------- AQUÍ PETA
      lista_contactos.add(contactos);
      } while (c.moveToNext());
      ---------------------------------------------------
      Llevo toda la tarde y no veo el error, en el main tengo:

      Bitmap image = BitmapFactory.decodeResource(getResources(),R.drawable.oro);

      // convert bitmap to byte
      ByteArrayOutputStream stream = new ByteArrayOutputStream();
      image.compress(Bitmap.CompressFormat.JPEG, 100, stream);
      byte[] imageInByte = stream.toByteArray();

      db.insertarANIMAL(1, "Pedro", 111111111, "pedro@DB.es",imageInByte);
      db.insertarANIMAL(2, "Sandra", 222222222, "sandra@DB.es",imageInByte);

      -----------------------
      Por lo que veo al hacer debug, me va cogiendo bien los datos del 1,Pedro,1111111,pedro@tal
      pero al llegar a la imagen peta.

      sabes por qué puede ser ? La CREATE TABLE tiene el campo "foto" como blob

      Eliminar
    4. Prueba a almacenar en el objeto "ALobos contactos" un bitmap en lugar de un array de bytes, es decir, en este punto:

      contactos.setID(c.getInt(0));
      contactos.setNOMBRE(c.getString(1));
      contactos.setTELEFONO(c.getInt(2));
      contactos.setEMAIL(c.getString(3));

      contactos.setFOTO(c.getBlob(4)); <---------------- ESTE

      Almacena en ese lugar un bitmap de la siguiente manera:

      Bitmap imagen = BitmapFactory.decodeByteArray(c.getBlob(4), 0, c.getBlob(4).length);
      contactos.setFOTO(imagen);
      (A parte adapta el constructor y los metodos para que manejen el bitmap en lugar del array bytes)

      En principio la parte de base de datos la estas haciendo bien, el tema de almacenar los datos en el objeto "ALobos contactos" habria que revisarlo y ver exactamente cual es el fallo que marca el log.

      Eliminar
  17. Hola ante todo muy buen tutorial. Tengo una duda. Quisiera saber como trabajar con varias tablas. Por ejemplo buscar un registro en la primer tabla, buscar otro registro en la segunda tabla y grabar.en la tarcer tabla los datos que busque de.la tabla 1 y 2.espero que me puedas ayudar.!
    Gracias!

    Gabriel

    ResponderEliminar
    Respuestas
    1. Te digo como yo lo hago.
      Tengo una clase que me sirve de fachada ante las conexiones a la base de datos, llamémosla FacadeDB, en ésta existe un campo (un objeto) de una clase que extienda a SQLiteOpenHelper (en mi caso es la única clase que extiende a este "ayudante", y es en el método onCreate donde se ejecuta el código necesario para generar las diferentes tablas con la llamada al método execSQL), llamémosla GeneralDBConnector. Además la clase FacadeDB, también utiliza otros dos objetos que son los encargados de realizar todo el conjunto de operaciones CRUD, y en cuyos constructores se les pasa una copia de la clase GeneralDBConnector (podemos llamarlos ClaseCRUD1, ClaseCRUD2 y ClaseCRUD3, donde cada uno de ellos realizará este tipo de operaciones CRUD sobre un única tabla TABLA_1, TABLA_2, y TABLA_3). La instanciación de esos campos utilizados en FacadeDB se puede hacer en su constructor, de esta manera quedaría:

      public FacadeDB(Context context) //El objeto Context se lo puedes pasar desde cualquier activity.
      {
      general = new GeneralDBConnector(context);
      crud1 = new ClaseCRUD1(general);
      crud2 = new ClaseCRUD2(general);
      crud3 = new ClaseCRUD3(general);
      }

      Cada una de las clases que realize las conexiones a la base de datos, guardará una copia de esa clase GeneralDBConnector, así, sus métodos constructores (y un método de extracción por el id) serían algo como(aunque le hemos pasado un GeneralDBConnector, y el constructor espera un SQLiteOpenHelper, al ser descendiente una de otra todo está correcto) :

      public ClaseCRUD1(SQLiteOpenHelper general)
      {
      this.general = general;
      }

      public Clase_1_GuardadaEnDB getClase(int id)
      {
      SQLiteDatabase db = general.getReadableDatabase();
      Clase_1_GuardadaEnDB clase;
      String selectQuery = "EXTRACCION DE LA TABLA_1" + id;
      Cursor cursor = db.rawQuery(selectQuery, null);
      if (cursor.moveToFirst())
      {
      clase = new ClaseGuardadEnDB(cursor.geStrin(1).....etc....);
      }
      db.close();
      return clase;
      }

      De vuelta a la clase Facade, si quieres extraer datos de dos tablas y meterlos en una única tabla sería algo como (esto es un método de Facade):

      public void sortTable1_and_Table2(int id_1, int id_2)
      {
      Clase_1_GuardadaEnDB clase1 = crud1.getClase(id_1);
      Clase_2_GuardadaEnDB clase2 = crud2.getClase(id_2);
      crud3.addClase(clase1, clase2);
      }


      Para ser más eficiente... o mejor dicho para tener una mejor estructuración de la jerarquía de las clases la clase FacadeDB es en realidad un Singleton, con lo que su constructor e privado y para instanciarla se utiliza un método estático generalmente llamado getInstance, que devuelve un objeto de tipo static de la clase FacadeDB).

      Eliminar
    2. Gracias por contestar eloy, ultimamente estoy muy liado y no tengo tiempo para dedicarlo al blog.

      Tu solucion esta bien para los que no tenemos conocimientos en sentencias SQL. He estado hechando un ojo por google y encontre estos dos hilos en stackoverflow:

      http://stackoverflow.com/questions/2529656/how-can-i-select-records-from-two-different-tables-in-one-mysql-query

      http://stackoverflow.com/questions/12890071/select-from-multiple-tables-mysql

      En los dos casos explica como hacer una consulta a una base de datos con dos tablas. (Las dos formas de hacerlo son validas, lo unico que al hacerlo por sentencias SQL te ahorras algo mas de codigo).

      La forma de hacerlo ya depende del desarrollador, en google hay muchos tutoriales sobre el uso de la sintaxis SQL.

      Eliminar
  18. Hola, buenos días.
    Quiero hacer la actualización de una entrada de una tabla con el método db.update (siendo db una instancia de la clase SQLiteDatabase). Para un sólo "ingrediente" en la clausula where y sus argumentos sería algo como:

    update(TABLA, nuevosValores, "campoX = ?", new String[] {"argumento_para_coincidencia_del campoX"});

    Pero... si quisiera hacer que hubiera más de un criterio en la clausula where... cómo se haría??

    update(TABLA, nuevosValores, "campoX = ? AND campoY=?", new String[] {"arg_campoX", "arg_campoY"});

    ¿Estaría bien el AND, o habría que poner una coma entre ambos campos? o qué?

    GRACIAS.

    ResponderEliminar
    Respuestas
    1. Estoy un poco perdido en sintaxis SQL pero por lo que he podido ver en google tu segundo ejemplo seria el valido:

      update(TABLA, nuevosValores, "campoX = ? AND campoY=?", new String[] {"arg_campoX", "arg_campoY"});

      Se puede utilizar AND y OR, al igual que se utiliza en java. Hechale un ojo a este articulo que te sacara de dudas:

      http://www.w3schools.com/sql/sql_and_or.asp

      Eliminar
  19. Hola muchas gracias por el tutorial. Tengo una pregunta a la que no paro de darle vueltas e intentar. Si quisiese hacer un boton consultar para que al pulsar me saliesen todos los contactos de la base de datos como lo tendría que hacer? gracias, espero que alguien me pueda ayudar :(

    ResponderEliminar
    Respuestas
    1. Lo tienes practicamente hecho. Necesitas hacer un listener del boton "CONSULTA":
      ponerlo en el mainactivity-OnCreate:
      Button Calibrar=(Button) findbyid(R.id.nombredelbotoneneldiseñodepantallalayout)
      Calibrar.setOnClickListener(new View.OnClickListener() {

      @Override
      public void onClick(View v) {
      seleccion();
      }
      });

      Y crear una funcion seleccion:
      private void seleccion(){
      //Recorrer la tabla
      int total=db.recuperarContacto().size();
      for (int j=0;j<total;j++)
      {
      //Hacer lo que quieras con cada elemento (mostrar por ejemplo en textview o listas)
      int[] ids = new int[db.recuperarContacto().size()];
      ids[j] = db.recuperarANIMAL().get(i).getID();
      noms[j] = db.recuperarContacto().get(i).getNOMBRE();
      tlfs[j] = db.recuperarContacto().get(i).getTELEFONO();
      emls[j] = db.recuperarContacto().get(i).getEMAIL();

      //Esas variables son las que tienes que poner donde quieras

      }
      }

      Eliminar
    2. podrias hacer uno asi pero completo sacando una lista

      Eliminar
  20. Amigo haces tutoriales ?? estaría bueno que subieras uno de este tema porque eres un maestro para esto mi profesor no enseña nada de esto

    ResponderEliminar
    Respuestas
    1. amigo y una pregunta porque no me sale nada en el layout me sale solo el hello word

      Eliminar
    2. Correcto, en la pantalla del movil no muestra nada. Solamente lo hace en el logcat de eclipse.

      Realmente no busco hacer tutoriales, simplemente utilizo el blog a modo de archivo. Voy repasando la guia para desarrolladores y cuando tengo tiempo subo algun resumen al blog. Pero ultimamente ando muy liado con un par de proyectos y no tengo tiempo para dedicarlo al blog.

      PD: Yo os agradezco el seguimiento pero con lo que hay publicado en el blog es mas que suficiente para ir aprendiendo a hacer las cosas.

      Eliminar
  21. hola amigo muchas gracias por el tutorial
    tenia una preguntita, en la parte 4
    puedo copiar una base de datos externa
    es decir la ruta puede ser la direccion ip de otra maquina donde este guardada la base de datos?

    ResponderEliminar
  22. Buenas excelente tu explicación me sirvió de mucho.
    Mi consulta es como evitar que los datos los borre el usuario los registros que se hicieron directamente desde el móvil. Como evitar que el usuario no borre los datos en administración de aplicaciones del móvil.

    ResponderEliminar
  23. una duda, el modo de crear los métodos para leer y registrar datos es el mismo?

    ResponderEliminar
  24. //Recuperamos los registros y los mostramos
    tengo mas de 500 datos tarda mucho al ejecutar la aplicacion como podria solucionar esa parte?

    ResponderEliminar
  25. Es el mejor ejemplo, el mas claro que pude conseguir,
    muchas gracias me ayudo un montón.

    ResponderEliminar
  26. hola, en la parte de copiar archivos me marca con rojo lo siguiente:

    InputStream IS = getApplicationContext().getAssets().open(archivo);

    getApplicationContext()

    cannot resolve method getApplicationContect()

    ResponderEliminar
  27. Buenas esta parte esta incorrecta no ? Me da error:

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

    Ya que el drop table tiene que ir seguido del nombre de la tabla solo.... despues ya la volvera a crear en el oncreate...

    drop table contactos en el on upgrade

    Estoy en lo cierto ?

    Gracias

    ResponderEliminar
  28. Hola estoy en las mismas tengo una duda deseo hacer dos botones para consultar al cursor donde estan cargados todos los datos de la tablay poderlos cargar en 3 textview uno int y dos strtring. La idea es de un boton adelante y otro atras para navergar sobre los registros cargados en el cursor. De antemano gracias a quien me pueda colaborar.

    ResponderEliminar
  29. eres un crack viejo nose si me vaya a funcionar pero al menos me aclaraste muchas dudas sobre base de datos gracias

    ResponderEliminar
  30. Holas tengo una duda cuando guardo datos del sqlite en el cel, se guarda en el archivo DATA pero no puedo acceder a ella...hay alguna solución para extraer ese dato en un archivo o guardarlo en la memoria externa?

    ResponderEliminar
  31. Hola, primero que todo, tengo que decir que soy nuevo en esto y estoy probando a hacer una app.

    Mi problema es que al inicio de la misma, me gustaría que apareciese un pequeño formulario que preguntase nombre, edad y peso. Según el usuario introduzca los datos, que estos se almacenen en su memoria interna y al abrir otro día la app, no tener que introducirlos de nuevo, sino que se conecte directamente a otro menú/pantalla con los datos guardados.

    Me gustaría que me dieseis algún consejo o algún link.

    ResponderEliminar
  32. Hola, primero que todo, tengo que decir que soy nuevo en esto y estoy probando a hacer una app.

    Mi problema es que al inicio de la misma, me gustaría que apareciese un pequeño formulario que preguntase nombre, edad y peso. Según el usuario introduzca los datos, que estos se almacenen en su memoria interna y al abrir otro día la app, no tener que introducirlos de nuevo, sino que se conecte directamente a otro menú/pantalla con los datos guardados.

    Me gustaría que me dieseis algún consejo o algún link.

    ResponderEliminar
  33. Excelente, también a mí me ha ayudado mucho. Gracias !!

    ResponderEliminar
  34. solo tengo que copiar el codigo tal cual y ya funcionará?

    ResponderEliminar
  35. hola como se puede hacer para que en mi movil aparesca la tabla? me super urge una ayuda amigooooooooooooooooooooooooooooooooooooo :(

    ResponderEliminar
  36. Hola agradezco que hayas compartido tu conocimiento con nosotros, tengo la siguiente duda como puedo insertar un dato a la tabla desde un spinner, es decir tengo una lista de productos los cuales los usuarios pueden colocar el número de unidades de cada uno de ellos, como debería hacer el proceso para que se guarde en la base de datos SQLite

    ResponderEliminar
  37. Hola agradezco tu aporte es de gran ayuda para los que estamos empezando en este medio, tengo la siguiente duda tengo 5 registros, id, nombre, telefono, correo, spinner como puedo guardar el valor del spinner dentro de una base de datos y posteriormente mostrar el dato guardado. Agradezco toda la ayuda que me puedas brindar es de gran ayuda para mi.

    ResponderEliminar
    Respuestas
    1. Amigo, tengo las misma duda, ¿ya lograste hacerlo?

      Eliminar
  38. hola tengo un problema, estoy implementado SQLite y no puedo agregar los datos ingresados, el programa que estoy haciendo es un poco avanzado, alguien le ha sucedido algo parecido?

    ResponderEliminar
  39. Hola, una vez más te agradezco en nombre de todos este tutorial. Escribo además porque en la parte de mostrar todos los registros me marca en rojo los metodos getID(), getDescripcion(), etc:

    // Recuperamos los 4 registros y los mostramos en el log
    Log.d("TOTAL", Integer.toString(MDB.recuperarArticulos().size()));
    int[] ids = new int[MDB.recuperarArticulos().size()];
    String[] descripciones = new String[MDB.recuperarArticulos().size()];
    float[] precioscosto = new float[MDB.recuperarArticulos().size()];
    float[] preciosventa = new float[MDB.recuperarArticulos().size()];
    int[] cantidades = new int[MDB.recuperarArticulos().size()];
    for (int i = 0; i < MDB.recuperarArticulos().size(); i++) {
    ids[i] = MDB.recuperarArticulos().get(i).getID();
    descripciones[i] = MDB.recuperarArticulos().get(i).getDescripcion();
    precioscosto[i] = MDB.recuperarArticulos().get(i).getPreciocosto();
    preciosventa[i] = MDB.recuperarArticulos().get(i).getPrecioventa();
    cantidades[i] = MDB.recuperarArticulos().get(i).getCantidad();
    Log.d(""+ids[i], descripciones[i] + ", " + precioscosto[i] + ", " + preciosventa[i] + ", " + cantidades[i]);
    }

    ResponderEliminar
    Respuestas
    1. ...a ver, siento mucho no haber sido más explícito: Estoy trabajando con Android Studio. "Que me marca en rojo" es que me está señalando que no reconoce esos métodos. si tienen alguna idea... Gracias!

      Eliminar
  40. hola tengo una app de base de datos hecha con sqlite y quisiera que esa base de datos la pudiera modificar y consultar otro usuario con su teléfono ¿como se puede hacer?

    ResponderEliminar
  41. El Baul De Android: Base De Datos Sqlite >>>>> Download Now

    >>>>> Download Full

    El Baul De Android: Base De Datos Sqlite >>>>> Download LINK

    >>>>> Download Now

    El Baul De Android: Base De Datos Sqlite >>>>> Download Full

    >>>>> Download LINK dJ

    ResponderEliminar