SQLITE
Transcript of SQLITE
1
SQLite
INTRODUCCIÓN
SqLite es un motor de base de datos creado en el año 2000 por el Dr. Richard Hipp.
Actualmente es el motor de bases de datos más utilizado en el mundo ya que se
encuentra presente en dispositivos con distintos sistemas operativos (Android, IOS,
Symbiam, etc.) y en Moizilla Firefox, PHP, Skype, Adobe AIR, etc.
Internamente, SQLite está construida por una pequeña librería multiplataforma
desarrollada en C que implementa un sistema gestor de bases de datos.
SQLite puede utilizarse para guardar datos que no requieran gran cantidad de
información como configuraciones, logs, historiales, etc. Actualmente SQLite 3 soporta
hasta 2 Terabytes, pero hay que tener en cuenta que SQLite consume al rededor de 256
bytes de memoria por cada 1 MiB de la base de datos.
SQLite es, como indican en un artículo de su propia web oficial, una base de datos de
código libre con las siguientes características distintivas:
No necesita configuración, ni tras la instalación inicial ni para el posterior
mantenimiento.
No utiliza servidor. Se puede utilizar embebida dentro de otra aplicación o
gestionar los ficheros de datos a través de una pequeña aplicación de consola
descargable desde su web.
Utiliza un sólo fichero para almacenar los datos. Una base de datos de
SQLite se compone de un único fichero que puede almacenarse en cualquier
ruta de la máquina.
Los ficheros de datos son multiplataforma. Una base de datos creada en una
máquina y sistema operativo concreto puede copiarse y utilizarse bajo
cualquier otra plataforma.
Es muy compacta. La librería que se integra con otras aplicaciones ocupa
unos 200 KBytes.
Utiliza tipado dinámico (Manifest Typing). SQLite permite almacenar
cualquier valor de cualquier tipo en cualquier registro de una tabla de la base
de datos, independientemente del tipo declarado al crear la tabla.
Utiliza registros de longitud variable. Cada dato almacenado en la base de
datos ocupará su tamaño real y no el reservado según su tipo.
SQLite, utiliza el lenguaje SQL para las consultas (SELECT), manipulación de datos
(INSERT, DELETE, etc.), y de definición de datos (CREATE TABLE, etc).
2
SQLite presenta unas pequeñas variaciones del estándar SQL-92 que aplica para la
mayoría de bases de datos SQL, por ello como no permite el uso de FOREIGN KEY,
RIGHT OTHER JOIN, FULL OTHER JOIN y algunos usos de ALTER TABLE.
Las bases de datos SQLite sólo pueden ser accedidas por la aplicación en la que fueron
creadas. En caso de necesitar compartir la base de datos en distintas aplicaciones se
deben utilizar Content Providers.
Las bases de datos SQLite se almacenan en la carpeta data/data/[nombre
paquete]/databases/nombreBaseDatos
La carpeta donde está almacenada la base de datos no es accesible por los usuarios
convencionales, tan sólo puede acceder el usuario root.
La ruta de data nos la puede aportar la orden Evironment.getDataDirector()
Desde el dispositivo virtual sí se puede acceder a la carpeta donde está la base de datos.
RESUMEN SQL
Inserción INSERT INTO "nombre_tabla”
("columna1", "columna2", ...)
VALUES ("valor1", "valor2", ...)
Modificación UPDATE "nombre_tabla"
SET "columna_1" = [nuevo valor]
WHERE {condición}
Eliminación DELETE FROM "nombre_tabla"
WHERE {condición}
Consulta SELECT
"nombre1_columna", "nombre2_columna"
FROM "nombre_tabla"
WHERE {condición}
ORDER BY "nombre_columna" [ASC, DESC]
3
CLASE SQLiteOpenHelper
Lo primero que haremos es crear una clase que herede de SQLiteOpenHelper. Esta
clase nos permite crear la base de datos y actualizar la estructura de tablas y datos
iniciales.
Debemos implementar el constructor y sobrescribir los métodos onCreate() y
onUpgrade().
El método onCreate() es llamado cuando la base de datos se crea por primera vez. Aquí
es donde se define la estructura de las tablas y se cargan eventualmente los datos
iniciales. Para ejecutar las sentencias SQL se dispone del método exexSQL(“orden
SQL”) de la instancia de SQLiteDatabase que se recibe por parámetro.
El método onUpgrade() se ejecuta automáticamente cuando se requiera de una
actualización de la base de datos (agregar/eliminar/modificar tablas o/y campos). En los
parámetros del método onUpgrade() se recibe un identificativo de la antigua versión y
de la versión nueva.
En nuestro ejemplo implementaremos una nueva clase llamada BaseDatos que herede
de la clase SQLiteOpenHelper:
public class BaseDatosHelper extends SQLiteOpenHelper {
public BaseDatosHelper (Context context, String nombre,
CursorFactory factory, int version) {
super(context, nombre, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table usuarios (id int primary key, nombre text, pasword
text, email text)");
4
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists usuarios");
db.execSQL("create table usuarios (id int primary key, nombre text, pasword
text, email text)");
}
}
USAR UNA BASE DE DATOS
Cuando ya se ha definido la base de datos en la clase que extiende de
SQLiteOpenHelper, el siguiente paso será utilizar la base de datos para acceder a la
información que contiene.
La escritura/lectura de la base de datos requiere de una referencia de la clase
SQLiteDataBase que provee los métodos insert(), update(), delete(),query(),
rawQuery() y execSQL().
execSQL(String sql): siendo sql una instrucción: CREATE, INSERT,
UPDATE y DELETE
rawQuery(String sql, String[] args): siendo sql una instrucción de tipo
SELECT
query(): permite realizar operaciones de consulta
delete(): permite eliminar registros
insert(): permite insertar registros
update(): permite actualizar registros.
Para acceder a la base de datos debemos seguir los siguientes pasos
1. Crear un objeto de la clase BaseDatosHelper y establecer la conexión
2. Abrir la base de datos para lectura o/y escritura.
3. Leer o/y escribir datos en la base de datos.
Crear un objeto de la clase BaseDatosHelper y establecer la conexión
BaseDatosHelper bdHelper =
new BaseDatosHelper (this, nombre, null, version)
Donde:
this: contexto de la actividad actual
nombre: cadena que representa el nombre con el que identificar a la base de
datos
null: objeto CursorFactory que normalmente no es necesario, nosotros
utilizaremos null.
5
versión: número entero que identifica la versión actual con la que queremos
trabajar, si la versión fuese superior a la ya existente se ejecutaría el método
onUpgrade() de la clase BaseDatosHelper.
Al crear un objeto de la clase BaseDatosHelper se producen de forma automática las
siguientes operaciones:
a) Si la base de datos no está creada, se procede a la ejecución del método
onCreate() de la clase BaseDatosHelper.
b) Si el número de versión es superior al de la base de datos existente, se ejecuta el
método onUpgrade() de la clase BaseDatosHelper
c) Si la base de datos ya existe y la versión que se demanda es la misma que la ya
existente, simplemente se abre la conexión con la base de datos.
Abrir la base de datos para lectura o escritura.
Cuando la conexión con la base de datos ya está establecida, se procederá a la apertura
de la base de datos.
A la hora de abrir la base de datos debemos indicar si las operaciones que vamos a
realizar son sólo de lectura o también lo son de escritura.
Para abrir la base de datos en forma de “solo lectura” se debe ejecutar el método
getReadableDatabase() sobre la instancia de BaseDatosHelper.
SQLiteDatabase bd= bdHelper.getReadableDatabase();
Para abrir la base de datos en forma de “lectura/escritura” se debe ejecutar el método
getWritableDatabase() sobre la instancia de la base de datos
SQLiteDatabase bd = bdHelper.getWritableDatabase();
Estos métodos devuelven una instancia de SQLiteDatabase que permite utilizar el
método execSQL() para ejecutar cualquier instrucción SQL de manipulación de datos.
Leer o/y escribir datos en la base de datos
Una vez abierta la base de datos, podemos acceder a la información que contiene para
leer o/y escribir datos a partir de la referencia de SQLiteDatabase creada (db)
Por ejemplo, el siguiente código abre la base de datos para escritura y le incorpora 3
registros.
public class MiBaseDatos extends Activity{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Abrir la conexión con la base de datos
6
BaseDatosHelper dbHelper=
new BaseDatosHelper (this, "UsuariosBD", null, 1);
//Abrir la base de datos 'UsuariosBD' en modo escritura
SQLiteDatabase db = dbHelper.getWritableDatabase();
//Si hemos abierto correctamente la base de datos
if(db != null){
//Insertar 4 usuarios
for(int i=1; i<=3; i++){
//Generar los datos
int codigo = i;
String nombre = "Usuario" + i;
//Insertar los datos en la tabla Usuarios
db.execSQL("INSERT INTO Usuarios (codigo, nombre) VALUES ?, ?",
new String[]{String.ValueOf(código),nombre});
}
//Cerrar la base de datos
db.close();
}
}
}
rawQuery y execSQL
Cursor rawQuery (String sql, String[] selecArgs )
sql: consulta SQL a ejecutar
selecArgs: array de argumentos a sustituir por las ? que existan en la
consulta sql
retorno: cursor posicionado en la primera entrada.
void execSQL (String sql)
sql: consulta SQL a ejecutar
No devuelve resultados
PATRÓN DE CAPAS
El patrón arquitectónico llamado patrón de capas se utiliza para plantear muchas
soluciones a problemas más o menos complejos. Este patrón nos ayuda a separar las
distintas responsabilidades de la aplicación en lo que se denomina capas. De esta forma
habrá una capa encargada de tratar con el origen de datos (bases de datos, ficheros
XML. etc), otra capa destinada a la lógica de negocio de la aplicación (utilizar esos
datos obtenidos para realizar distintas operaciones) y otra capa destinada a presentar las
vistas (la parte de la interfaz de usuario).
7
La estructura de capas favorecer el mantenimiento de la aplicación, la reutilización del
código y su escalabilidad.
Para conocer este patrón analizaremos un ejemplo en el que se desea desarrollar un
sistema empresarial, donde se pretende manejar la información de presupuestos para los
clientes de la empresa. Es necesario conocer los precios internos, elaborar el
presupuesto, acceder al inventario de los productos, y contemplar los datos e historia del
cliente que pide el presupuesto. La información debe estar disponible para ser
consultada por la Web, y provenir de distintas fuentes de datos.
Se pretende organizar la arquitectura del sistema para que sea flexible, por ejemplo, que
contemple las distintas formas de acceder a los datos, y las formas de procesarlos, y por
último, los distintos modos de visualizar el resultado.
Podemos tomar la decisión de separar la aplicación según este esquema:
Este patrón debe evitar que el cambio en una capa altere mínimamente las otras capas.
La prueba más difícil, en nuestro ejemplo, podría ser: al cambiar las fuentes de datos
(las bases de datos usadas), poco debería afectar a la capa de presentación. Y si el día de
mañana queremos incorporar una capa de presentación distinta (como un sistema de
atención automática por teléfono), no debería alterar a las otras capas ya desarrolladas.
Si bien en este ejemplo, las capas que elegimos construir son las de presentación,
negocio y datos, el patrón es lo suficientemente general para aplicarse en otras
situaciones.
8
CAPA DE ACCESO A DATOS (DAL)
La capa de Acceso a Datos generalmente se compone de métodos que acceden a la base
de datos y devuelven objetos para ser tratados por otras capas. Esta capa debe ser lo más
independiente posible del tipo de tecnología utilizada para almacenar los datos. Los
métodos que componen esta capa son llamados por la capa de lógica de negocio, la cual
no tiene en cuenta el origen de datos. Esta capa debe realizar todas las conversiones y
validaciones necesarias que estén relacionadas con el modelo de base de datos.
La implementación de la capa de Acceso a Datos para una base de datos SQLite puede
ser como la siguiente
public class CapaAccesoDatos {
// Campos de la BD
public static final String ID = "_id";
public static final String NOMBRE = "nombre";
public static final String PASWORD = "pasword";
public static final String EMAIL = "email";
//Datos de la base de datos
public static final String DATABASE_TABLE = "Usuarios";
public static final String DATABASE = "BDUsuarios.db";
public static final int DATABASE_VERSION = 1;
//Objetos a utilizar
private Context context;
private SQLiteDatabase database;
private BaseDatosHelper dbHelper;
//Constructor
public CapaAccesoDatos(Context context) {
this.context = context;
}
//Cerrar la base de datos
public void close() {
dbHelper.close();
}
/*-------------------------------------------Otros método------------------------------------------*/
}
ContentValues
Para el manejo de los datos directamente sobre la base de datos utilizaremos la clase
ContentValues que permite crear y actualizar valores.
A través de la clase ContentValues se manipulan datos organizados en pares
identificador/valor, donde identificador es el nombre el campo y el valor su contenido.
9
A la clase CapaAccesoDatos debemos agregar los métodos que se prevean necesario
para el trabajo con la base de datos.
Insertar un registro
long insert (String table, String nullColumnaHack, ContentValues values)
table: nombre de la table
nullColumnHack: null o nombre de una columna si values no contiene
ningún par columna-valor.
values: conjunto de pares columna/valor que se quiere insertar
devuelve el id de la fila o -1 si hubo algún error
public long insertarUser (String nombre, String pasword, String email) {
long numReg;
database = dbHelper.getWritableDatabase();
ContentValues initialValues = createContentValues(nombre, pasword,
email);
numReg=database.insert(DATABASE_TABLE, null, initialValues);
dbHelper.close();
return numReg;
}
private ContentValues createContentValues(String nombre, String pasword,
String email) {
ContentValues values = new ContentValues();
values.put(NOMBRE, nombre);
values.put(PASWORD, pasword);
values.put(EMAIL, email);
return values ;
}
Este método devuelve -1 si no se ha podido realizar la tarea y el número de fila del
registro agregado en caso contrario.
Cursor
Una consulta devuelve un objeto de tipo Cursor. Un cursor es un puntero hacia al
primer elemento de la lista resultado de una consulta. De esa forma, Android, no tiene
que tener en memoria toda la tabla, sino tan sólo el resultado de la consulta.
Para moverse entre los distintos elementos de un objeto Cursor se pueden utilizar los
métodos: moveToFirs() y moveToNext(). El método isAfterLast() permite comprobar si
se ha alcanzado el final de la lista.
El número de elementos de un cursor se obtiene con el método getCount().
10
Para acceder a los datos individuales de un elemento de un objeto cursor se pueden
utilizar los métodos:
getLong(columnIndex) -> devuelve el dato de la columna cuyo orden de
secuencia es columnIndex y cuyo tipo de Long.
getString(columnIndex) -> devuelve el dato de la columna cuyo orden de
secuencia es columnIndex y cuyo tipo de String.
El método getColumnIndexOrThrow(String) devuelve el número de secuencia de la
columna cuyo nombre se pasa por parámetro.
Después de usar un cursor se debe cerrar con el método close().
Acceso a todos los elementos de una tabla
En la clase CapaAccesoDatos se debe incluir un método que seleccione todos los
registros de una tabla.
Cursor query (String tabla, String[] columns, String whereClause, String[]
whereArgs, String groupBy, String having, String orderBy)
tabla: Nombre de la tabla
columns: columnas a devolver, si se pasa null se devuelven todas las
columnas
whereClause: condición WHERE o null para acceder a todas las filas
(“ID=?”)
whereArgs: lista de Strings que sustituyen a ¿, o null (new
String[]{“1”,”3”,”5”)
groupBy: Argumentos de GROUP BY, o null si no se aplica.
having: Argumentos de HAVING, o null si no se aplica.
orderBy: Argumentos de ORDER BY, o null si no se aplica.
retorno: Un cursor posicionado en la primera entrada
//Devuelve el Cursor que contiene todos los ítems
public Cursor todosUser(){
database = dbHelper.getReadableDatabase();
Cursor elCursor = database.query(DATABASE_TABLE, new String[] {
ID, NOMBRE, PASWORD, EMAIL },null, null, null, null, null);
return elCursor;
}
Para acceder a todos los elementos de la tabla desde una actividad cualquiera:
try{
//Crear una instancia de la capa de acceso a datos
miBaseDatos=new CapaAccesoDatos(this);
//Cargar toda la base de datos
miBaseDatos.CargarBaseDatos();
}catch (Exception e){
11
Log.e("MIO",e.toString());}
Cursor cursor= miBaseDatos.todosUser();//Crear un cursor para acceder a los datos.
if (cursor.moveToFirst()) {
//Recorremos el cursor hasta que no haya más registros
do {
String usuario = cursor.getString(1);
String pasword = cursor.getString(2);
String email = cursor.getString(3);
info.setText(info.getText()+"\n user: "+usuario+" pasword: "+pasword+"
email:"+email);
} while(cursor.moveToNext());
}
Devuelve un cursor con el registro que tiene un id
public Cursor unUser(long id){
Cursor elCursor = database.query(DATABASE_TABLE, new String[]
{ID, NOMBRE, PASWORD, EMAIL }, ID + "=?",
new String[]{String.ValueOf(código)}, null, null, null);
if (elCursor != null) {
elCursor.moveToFirst();
}
return elCursor;
}
Devuelve un cursor con el registro con el nombre de usuario indicado
public Cursor verPasword(String nombre){
Cursor elCursor = database.query(DATABASE_TABLE, new String[] {
ID, NOMBRE, PASWORD, EMAIL },
NOMBRE + "=?", new String[]{nombre}, null, null, null);
if (elCursor != null) {
elCursor.moveToFirst();}
return elCursor;
}
Actualizar un registro
int update (String table, ContentValues, values, String whereClause, String[]
whereArgs)
table: Nombre de la tabla
values: pares columna/valor
whereClause: condición de WHERE (_id=?)
whereArgs: lista de Strings que sustituyen a ¿, o null (new String[]{“1”,”3”,”5”)
12
retorno: número de filas afectadas
public long updateUser(long id, String nombre, String pasword,
String email) {
ContentValues updateValues = createContentValues(nombre, pasword, email);
return database.update(DATABASE_TABLE, updateValues, ID + "=?",new
String[]{String.valueOf(id)});
}
Eliminar un registro
int delete (String Table, String whereClause, String[] whereArgs
table: Nombre de la tabla
whereClause: condición de WHERE (_id=?)
whereArgs: lista de Strings que sustituyen a ¿, o null (new String[]{“1”,”3”,”5”)
retorno: número de filas afectadas si la clausula Where no es null, 0 si lo es.
public long deleteUser(long id) {
return database.delete(DATABASE_TABLE, ID + "=" + id, null);
}
ESTRUCTURA DE CLASES DE LA CAPA DAL
La estructura de clases de la capas e acceso a datos quedará de la siguiente forma:
DAOSDFSDFS
Nota: Una buena práctica es crear una clase por tabla y almacenar los datos obtenidos
por el cursor en un array de la clase de objeto correspondiente.
Activity
DAL
13
VER LOS ELEMENTOS EN UNA LISTA
Se puede utilizar el adaptador SimpleCursorAdapter para cargar un elemento ListView
con un elemento Cursor que sea resultado de una consulta en una base de datos SQLite.
Los pasos para realizar esta operación son:
1. Tener un elemento ListView en un layout o bien crear una Activity que extienda
de ListActivity.
2. Crear un layout para cada elemento de la fila del LisView.
3. Crear el SimpleCursorAdapter
4. Enlazar el adaptador a la lista.
Vamos a ver un ejemplo con un elemento ListView que exista en un layout
public void cargarListViewTodosUser(Cursor cursor){
//Nombres de los campos a utilizar en la lista
String[] FROM ={CapaAccesoDatos.NOMBRE, CapaAccesoDatos.PASWORD};
//Nombres de los controles donde situar el contenido de los campos indicados
//Estos controles pertenecen al layout de la fila del ListView
int[] TO= {R.id.textView1,R.id.textView2};
//Crear una instancia del control donde está el ListView
ListView miLista=(ListView) findViewById(R.id.list);
//Crear el adaptaer aportando el contexto, el recurso layout de la fila, el cursor,
//el nombre de los campos que quiero mostrar y los controles donde mostrarlos
SimpleCursorAdapter miAdaptador=new SimpleCursorAdapter (this,
R.layout.item_list, cursor, FROM,TO);
//Asignar el adaptador
miLista.setAdapter(miAdaptador);
}
Explicar mejor
ENLACES SQLite
http://sqlite-latino.blogspot.com.es/
http://www.vogella.de/articles/AndroidSQLite/article.html
http://www.higherpass.com/Android/Tutorials/Accessing-Data-With-Android-Cursors/
http://www.slideshare.net/paalvarador/sqlite-en-android
http://www.slideshare.net/CarlosIglesias3/tema-4-51accesodatos