SQLITE

13
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).

Transcript of SQLITE

Page 1: 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).

Page 2: SQLITE

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]

Page 3: SQLITE

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)");

Page 4: SQLITE

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.

Page 5: SQLITE

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

Page 6: SQLITE

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).

Page 7: SQLITE

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.

Page 8: SQLITE

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.

Page 9: SQLITE

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().

Page 10: SQLITE

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){

Page 11: SQLITE

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”)

Page 12: SQLITE

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

Page 13: SQLITE

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