X

Guardar Datos en Bases de Datos SQL

Guardar datos en bases de datos SQL es ideal para el almacenamiento repetitivo o estructurado de los mismos, como puede ser la información de los contactos. Esta lección asume que tu ya te has familiarizado con las bases de datos SQL de forma general y te ayudará a comenzar a utilizar las bases de datos SQLite en Android. Las APIs que necesitarás utilizar se encuentran disponibles en el paquete android.database.sqlite.

Definir un Esquema y un Convenio

Una de los principales principios de las bases de datos SQL es el esquema: una declaración formal de como se organiza la base de datos. El esquema se refleja en las declaraciones SQL que has usado para crear tu base de datos. Puedes encontrar útil crear una clase compañera, conocida como clase convenio, la cual especifica de forma explicita la disposición de tu esquema de un modo sistemático y autodocumentado.

Una clase convenio es un contenedor para las constantes que definen los nombres para los URIs, las tablas y las columnas. También te permite utilizar las mismas constantes a lo largo de las otras clases en el mismo paquete. Esto te permite cambiar el nombre de una columna en un lugar y propagarlo a través de tu código.

Una buena forma de organizar dicha clase es colocar las definiciones que son de carácter global de tu base de datos en el nivel raíz de la clase. Entonces creas una clase interna para cada tabla que enumera sus columnas.

Nota: Mediante la implementación de la interfaz BaseColumns, tu clase interna puede heredar una campo principal clave llamado _ID que algunas clases de Android como los adaptadores de cursos esperarán tener. No es necesario, pero puede ayudar a que tu base de datos funcione de forma armoniosa con el esquema Android.

Por ejemplo, este fragmento de código define el nombre de la tabla y los nombres de las columnas para una tabla:

public final class FeedReaderContract {
    // To prevent someone from accidentally instantiating the contract class,
    // give it an empty constructor.
    public FeedReaderContract() {}

    /* Inner class that defines the table contents */
    public static abstract class FeedEntry implements BaseColumns {
        public static final String TABLE_NAME = "entry";
        public static final String COLUMN_NAME_ENTRY_ID = "entryid";
        public static final String COLUMN_NAME_TITLE = "title";
        public static final String COLUMN_NAME_SUBTITLE = "subtitle";
        ...
    }
}

Crear una Base de Datos utilizando SQL Helper

Una vez has definido como se verá tu base de datos, deberías implementar los métodos que crean y mantienen la base de datos y las tablas. Estos son algunas declaraciones típicas que crean y eliminan una tabla:

private static final String TEXT_TYPE = " TEXT";
private static final String COMMA_SEP = ",";
private static final String SQL_CREATE_ENTRIES =
    "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" +
    FeedEntry._ID + " INTEGER PRIMARY KEY," +
    FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
    FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
    ... // Any other options for the CREATE command
    " )";

private static final String SQL_DELETE_ENTRIES =
    "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;

Igual que los archivos que guardas en el almacenamiento interno del dispositivo, Android almacena tu base de datos en un espacio de disco privado que se asocia con la aplicación. Tus datos estñan asegurados ya que, por defecto, esta área se encuentra inaccesible para otras aplicaciones.

Un conjunto de APIs útiles está disponible en la clase SQLiteOpenHelper. Cuando utilices esta clase para obtener referencias de tu base de datos, el sistema realiza operaciones potencialmente de larga duración de creación y actualización de la base de datos únicamente cuando sea necesario y no durante el inicio de la aplicación. Todo lo que necesitas hacer es llamar a getWritableDatabase()getReadableDatabase().

Nota: Ya que pueden ser de larga duración, asegúrate de que dichas llamadas se realizan en un hilo en segundo plano, como puede ser AsyncTask o IntentService.

Utilizar SQLiteOpenHelper, crea una subclase que sobrescribe los métodos onCreate()onUpgrade()onOpen(). También puedes querer implementar onDowngrade(), pero no necesario.

Por ejemplo, esta es una implementación de SQLiteOpenHelper que utiliza algunos de los comandos mostrados abajo:

public class FeedReaderDbHelper extends SQLiteOpenHelper {
    // If you change the database schema, you must increment the database version.
    public static final int DATABASE_VERSION = 1;
    public static final String DATABASE_NAME = "FeedReader.db";

    public FeedReaderDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(SQL_CREATE_ENTRIES);
    }
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // This database is only a cache for online data, so its upgrade policy is
        // to simply to discard the data and start over
        db.execSQL(SQL_DELETE_ENTRIES);
        onCreate(db);
    }
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        onUpgrade(db, oldVersion, newVersion);
    }
}

Para acceder a tu base de datos, haz una instancia de tu subclase de SqLiteOpenHelper:

FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());

Añadir Información a una Base de Datos

Puedes insertar datos en una base de datos mediante un objeto ContentValues gracias al método insert():

// Gets the data repository in write mode
SQLiteDatabase db = mDbHelper.getWritableDatabase();

// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, id);
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_CONTENT, content);

// Insert the new row, returning the primary key value of the new row
long newRowId;
newRowId = db.insert(
         FeedEntry.TABLE_NAME,
         FeedEntry.COLUMN_NAME_NULLABLE,
         values);

El primer argumento del método insert() es el nombre de la tabla. El segundo proporciona el nombre de una columna en la cual el sistema puede insertar NULL en el evento en el que ContentValues se encuentra vacío (si en su lugar lo colocas como “null“, el sistema no insertará una fila cuando no haya valores).

Leer la Información de una Base de Datos

Para leer una base de datos, utiliza el método query(), indicando tus criterios de selección y las columnas deseadas. El método combina los elementos insert()update(), excepto la lista de columnas que define los datos que quieres extraer, a diferencia de los datos a insertar. Los resultados de dicha petición vienen datos mediante un objeto Cursor.

SQLiteDatabase db = mDbHelper.getReadableDatabase();

// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
    FeedEntry._ID,
    FeedEntry.COLUMN_NAME_TITLE,
    FeedEntry.COLUMN_NAME_UPDATED,
    ...
    };

// How you want the results sorted in the resulting Cursor
String sortOrder =
    FeedEntry.COLUMN_NAME_UPDATED + " DESC";

Cursor c = db.query(
    FeedEntry.TABLE_NAME,  // The table to query
    projection,                               // The columns to return
    selection,                                // The columns for the WHERE clause
    selectionArgs,                            // The values for the WHERE clause
    null,                                     // don't group the rows
    null,                                     // don't filter by row groups
    sortOrder                                 // The sort order
    );

Para mirar una columna en el Cursor, utiliza los métodos para moverse a través del mismo, los cuales deben utilizar siempre antes de empezar a leer los valores. Generalmente deberías comenzar llamando a moveToFirst(), el cual coloca la “posición de lectura” en la primera entrada de los resultados. Para cada fila, puedes leer el valor de la columna mediante cualquiera de los métodos get, como puede ser getString()getLong(). Para cada uno de los mismos, debes indicar la posición del índice de la columna que desee, la cual puedes obtener mediante getColumnIndex()getColumnIndexorThrow(). Por ejemplo:

cursor.moveToFirst();
long itemId = cursor.getLong(
    cursor.getColumnIndexOrThrow(FeedEntry._ID)
);

Eliminar Información de una Base de Datos

Para eliminar las filas de una tabla, necesitas proporcionar los criterios de selección que identifican a las misma. La API de las bases de datos proporcionan mecanismos para crear criterios de selección que protegen contra la inyección SQL. El mecanismo se divide la especificación de selección en dos, una clausula y unos argumentos. La cláusula define las columnas donde buscar, y también te permite combinar las pruebas de columnas. Los argumentos son valores para probar cuales son los límites de la cláusula. Ya que los resultados no se gestionan del mismo modo que las sentencias SQL, es inmune a la inyección SQL.

// Define 'where' part of query.
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
// Specify arguments in placeholder order.
String[] selectionArgs = { String.valueOf(rowId) };
// Issue SQL statement.
db.delete(table_name, selection, selectionArgs);

Actualizar una Base de Datos

Cuando necesites modificar un subconjunto de valores de tu base de datos, utiliza el método update().

Actualizar la tabla combina la sintaxis de valores de contenido de insert() con la sintaxis where de delete().

SQLiteDatabase db = mDbHelper.getReadableDatabase();

// New value for one column
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);

// Which row to update, based on the ID
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(rowId) };

int count = db.update(
    FeedReaderDbHelper.FeedEntry.TABLE_NAME,
    values,
    selection,
    selectionArgs);

Puedes ver más información sobre Guardar Datos en Bases de Datos SQL en la página oficial de Google en inglés pulsando aquí.

Los comentarios de Disqus están cargando....