Bueno, pues antes de que pase más el tiempo, es hora de preparar esta charla para que todos las disfrutemos al máximo!

Algo importante mencionar es que todo se realizará desde la consola de comandos (xterm) y todos los aquí hecho ha sido usando la distro LinuxMint12, así que se podrán realizar sin problema en cualquier distro basada en Ubuntu o en Debian; para cualquier otra distro, es necesario revisar los comandos correspondientes para las instalación de paquetes.

Como todo esto será usando sólamente una terminal o consola de comandos pongo una advertencia de que esto es sólo para valientes y últimamente me ha parecido ver más valentía en el grupo fem… así que aponerse las pila ya!

Lo primero es abrir una terminal de comandos, en versiones resientes de Ubuntu 11.04 o más recientes o LinuxMint presionando la combinación de teclas Ctrl+Alt-T se abre una ventana que es la terminal de comando, de lo contrario hay que ir al menú de aplicaciones y por lo regular en accesorios hay una opción llamada terminar, dar click en ese icono y entonces tendremos algo como lo siguiente:

ahora si todo listo para iniciar y todos los comandos deberán ser ejecutado en una terminal como la anterior, se puede incluso abrir más de una para talves en una ver resultados y en otra ejecutar los comandos.

Temas a tratar:

  1. Porque SQLite3
  2. Instalación de SQLite3
  3. Aprendiendo a usar SQLite3 en 5min
    1. Crear una base de datos y una tabla
    2. Insertar datos
    3. Crear una consulta
  4. Instalando PySQLite
  5. Aprendiendo a usar PySQLite
    1. Usando el módulo en tiempo real (esto me facina!)
    2. Usando el módulo desde un script
    3. Ejemplo: Exportar datos a CSV
  6. Caso práctico 1: Crear una aplicación ToDo (si el tiempo lo permite)
  7. Caso práctico 2: Crear un script para monitorear si hay algún cambio en algún elemento de una base de datos. (si las neuronas lo permiten!)

1. Porque SQLite3

SQLite3 es un sistema de librerías que permite tener una base de datos SQL sin la necesidad de tener un RDBMS por separado, de tal forma que, la base de datos, pueda ser embebida con la misma aplicación y según su documentación en algunas operaciones es incluso mucho más rápido de MySQL o Postgres.

Aplicaciones como Firefox/Mozilla usan SQLite para guardar datos de forma local, lo que pinta muy bien para aplicaciones de escritorio o mejor aún para aplicaciones móviles y aquí es donde sólo la imaginación tiene límite… veamos!

Para más información visitar el sitio principal SQLite
Para conocer el desarrollo de librerías para un lenguaje de programación visitar el wiki SQLite Wrappers

2. Instalación de SQLite3

Lo primero es revisar si está o no instalado el cliente para sqlite3, para ello se usará el siguiente comando:

$ dpkg -l sqlite3*
No se ha encontrado ningún paquete que corresponda con sqlite3*.
$

Si aparece algo como lo anterior, entonces el cliente de sqlite no está instalado y obiamente sólo resta una cosa por hacer…

$ sudo apt-get install sqlite3 sqlite3-doc
...
$

El paquete sqlite es un cliente que permite crear y administrar bases de datos desde la línea de comandos y el paquete sqlite3-doc contiene documentación muy completa para consultar sin la necesidad de tener una conexión a Internet.

La documentación se puede acceder usando cualquier navegador y abriendo el archivo /usr/share/doc/sqlite3-doc/index.html y se verá como lo siguiente

ahora para verificar que SQLite3 y su documentación están correctamente instalados se ejecuta nuevamente el siguiente comando

 $ dpkg -l sqlite*
 Deseado=Desconocido/Instalar/Eliminar/Purgar/Retener
 | Estado=No/Instalado/Config-files/Desempaquetado/Medio-conf/Medio-inst/espera-disparo/pendiente-disparo
 |/ Err?=(ninguno)/Requiere-reinst (Estado,Err: mayúsc.=malo)
 ||/ Nombre         Versión       Descripción
 +++-==============-==============-============================================
 ii  sqlite3        3.7.7-2ubuntu2 Command line interface for SQLite 3
 ii  sqlite3-doc    3.7.7-2ubuntu2 SQLite 3 documentation $

ahora se observa que ambos paquetes aparecen instalados y el número de versión.

3. Aprendiendo a usar SQLite3 en 5min.

3.1 Creando una base de datos

Ahora toca crear una base de datos llamada teamparty y una tabla llamada tContact con los campos id, name, sex y movil como sigue

$ sqlite3 teamparty
SQLite version 3.7.7 2011-06-23 19:49:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table tContact (id INTEGER PRIMARY KEY, name VARCHAR(100), sex varchar(1), movil VARCHAR(12));
sqlite> .table
tContact
sqlite> .schema tContact
CREATE TABLE tContact (id INTEGER PRIMARY KEY, name VARCHAR(100), sex varchar(1), movil VARCHAR(12));
sqlite> .quit
$ ls -lF
total 4
-rw-r--r-- 1 vipper vipper 2048 2012-01-24 03:58 teamparty

La creación de la tabla se hace usando la conocida instrucción SQL create table nombre, para ver una lista de las tablas creadas, se usa el comando .table, para ver el esquema de dicha tabla se usa el comando .schema nombre.

Al salir del cliente de sqlite, se observa que se ha creado un archivo con el mismo nombre de la base de datos, sin embargo es recomendable dar la extensión sqlite3 para así identificar que el archivos es una base de datos SQLite3, por lo que procedemos a borrar y crear nuevamente la base de datos…

$ rm teamparty
$ sqlite3 teamparty.sqlite3
SQLite version 3.7.7 2011-06-23 19:49:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table tContact (id INTEGER PRIMARY KEY, name VARCHAR(100), sex varchar(1), movil VARCHAR(12));
sqlite> .table
tContact
sqlite> .schema tContact
CREATE TABLE tContact (id INTEGER PRIMARY KEY, name VARCHAR(100), sex varchar(1), movil VARCHAR(12));
sqlite> .quit
$ ls -lF
total 4
-rw-r--r-- 1 vipper vipper 2048 2012-01-24 04:01 teamparty.sqlite3
$

Otra manera sería haber renombrar el archivo simplemente, pero a veces nos gusta el camino dificil!

3.2 Insertar datos

Y bueno una tabla no sirve de mucho si no tiene datos, así que hay que agregar unos cuantos registros

$ sqlite3 teamparty.sqlite3
SQLite version 3.7.7 2011-06-23 19:49:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .table
tContact
sqlite> .schema tContact
CREATE TABLE tContact (id INTEGER PRIMARY KEY, name VARCHAR(100), sex varchar(1), movil VARCHAR(12));
sqlite> INSERT INTO tContact (name, sex, movil) VALUES ("Ricardo Torres", "1", "55 1832 4944");
sqlite> INSERT INTO tContact (name, sex, movil) VALUES ("Mario Martinez", "1", "55 4944 1832");
sqlite> INSERT INTO tContact (name, sex, movil) VALUES ("Morticia Adams", "0", "55 0000 0000");
sqlite> INSERT INTO tContact (name, sex, movil) VALUES ("Ricky Marti", "0.5", "55 0123 3210");
sqlite> .quit

con esto insertamos 4 registros y si como todos se habrán dado cuenta no se ha colocado calor alguno para id, aunque existe otra forma de insertar datos y en general de realizar cualquier operación y es como sigue

$ sqlite3 teamparty.sqlite3
$ sqlite3 teamparty.sqlite3 "INSERT INTO tContact (name, sex, movil) VALUES ('invitada 1', '0', '55 0123 LLAMA');"
$ sqlite3 teamparty.sqlite3 "INSERT INTO tContact (name, sex, movil) VALUES ('invitada 2', '0', '55 BUEN AS00');"
$

3.3 Crear una consulta

Las consultas se crean usando el ya conocido SELECT y como ejemplo

$ sqlite3 teamparty.sqlite3 "SELECT * FROM tContact;"
1|Ricardo Torres|1|55 1832 4944
2|Mario Martinez|1|55 4944 1832
3|Morticia Adams|0|55 0000 0000
4|Ricky Marti|0.5|55 0123 3210
5|invitada 1|0|55 0123 LLAMA
6|invitada 2|0|55 BUEN AS00
$

lo anterior coincide claramente con el resultado esperado y sólo notar que el valor del campo id se fué auto incrementando conforme se adicionaba cada uno de los registros.

4. Instalando PySQLite

De fábrica prácticamente casi toda distro de Linux trae instalado Python, pero para poder usar bases de datos SQLite3, es necesario instalar el módulo llamado PySQLite y nuevamente para distros basadas en Ubuntu o Debian como lo es LinuxMint12, la instalación es muy simple; para cualquier otra distro hay que usar el comando adecuado para instalar los paquetes necesarios.

Primero hay que averiguar cual es el nombre del paquete a instalar

$ apt-cache search pysqlite
python-sqlite - Python interface to SQLite 2
python-pysqlite1.1-dbg - interfaz python para SQLite 3 (extensión de depuración)
python-pysqlite2 - interfaz Python para SQLite 3
python-pysqlite2-dbg - interfaz Python para SQLite 3 (extensión de depuración)
python-pysqlite2-doc - Documentación para python-pysqlite2
python-sqlite-dbg - Python interface to SQLite 2 (debug extension)

se puede observa que el paquete con el nombre python-pysqlite2 es el que necesitamos ya que corresponde a SQLite3, así que se instala con

$ sudo apt-get install python-pysqlite2 python-pysqlite2-doc
Reading package lists... Done
...
$

adicionalmente he instalado el paquete python-pysqlite2-doc que contiene la documentación de ayuda para pysqlite y que se puede consultar abriendo el archivo /usr/share/doc/python-pysqlite2-doc/html/index.html

se sugiere dar click en Module Index y luego en sqlite3, con eso se obtendrá una muy buena referencia de todo lo que se puede hacer con el módulo.

y bueno ya tenemos auto y carretera, ahora si a conducir!

5. Aprendiendo a usar SQLite

5.1 Usando el módulo en tiempo real

Para usar el módulo de esta manera primero hay que iniciar una sesión de python de la siguiente manera:

$ python
Python 2.7.2+ (default, Oct  4 2011, 20:06:09)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

Ahora, lo primero es llamar el módulo de pysqlite en la sesión iteractiva de python

>>> import sqlite3
>>>

Ahora para poder usar una base de datos sqlite, es necesario crear un objeto Connection y un objeto Cursor.

El objeto Connection es el que representa toda la base de datos y es donde se indica donde son almacenados los datos que pudiera ser en un archivo o incluso en la memoria haciendo uso del nombre de archivo especial «:memory:»

El objeto Cursor tiene un método llamado execute() que permite realizar comandos SQL.

>>> conn = sqlite3.connect('teamcoffe.sqlite3')
>>> c = conn.cursor()
>>>

lo anteior hace uso de la base de datos llamada teamcoffe y se usará la variable c para realizar todas las operaciones, como por ejemplo crear una tabla e insertar algunos valores

>>> c.execute('''create table tContact
...             (id INTEGER PRIMARY KEY,
...             name VARCHAR(100),
...             email VARCHAR(100),
...             twtter VARCHAR(100))''')
<sqlite3.Cursor object at 0x111f5e0>
>>> c.execute('''INSERT INTO tContact (name, email, twtter)
...             VALUES ("Ricardo Torres","rictor@cuhrt.com","@rctorr")''')
<sqlite3.Cursor object at 0x111f5e0>
>>> c.execute('''INSERT INTO tContact (name, email, twtter)
...             VALUES ("Mario Martinez","mortiz@gmail.com","@mortiz")''')
<sqlite3.Cursor object at 0x111f5e0>
>>> conn.commit()
>>> c.close()
>>>

Como se puede observar con el método execute() es con el que se ejecutan todas las intrucciones de SQL, en este caso para crear la tabla tContact y para insertar dos registros en la tabla.

Para que los cambios se haga efectivo, se tiene que ejectuar el método commit() del objeto Connect y para cerrar el acceso a la base de datos se usa el método close() del objeto Cursor.

Ahora veamos como podemos realizar una simple consulta

>>> conn = sqlite3.connect('teamparty.sqlite3')
>>> c = conn.cursor()
>>> c.execute('''SELECT * FROM tContact ORDER BY name''')
<sqlite3.Cursor object at 0x14f25e0>
>>> for row in c:
...     print row
...
(2, u'Mario Martinez', u'1', u'55 4944 1832')
(3, u'Morticia Adams', u'0', u'55 0000 0000')
(1, u'Ricardo Torres', u'1', u'55 1832 4944')
(4, u'Ricky Marti', u'0.5', u'55 0123 3210')
(5, u'invitada 1', u'0', u'55 0123 LLAMA')
(6, u'invitada 2', u'0', u'55 BUEN AS00')
>>>

como se puede ver al ejecutar la consulta lo que se obtiene es un valor que en apariencia no tiene nada que ver con la consulta, en realidad es una referencia al objeto mismo y para poder observar el contenido del objeto hay que iterar sobre cada uno de sus elementos, por esa razón se usa el for.

Si se desea obtener una lista conteniendo todos los renglones resultantes, se puede hacer uso del método fetchall como sigue:

>>> c.execute('''SELECT * FROM tContact ORDER BY name''')
<sqlite3.Cursor object at 0x14f25e0>
>>> l = c.fetchall()
>>> l
[(2, u'Mario Martinez', u'1', u'55 4944 1832'), (3, u'Morticia Adams', u'0', u'55 0000 0000'), (1, u'Ricardo Torres', u'1', u'55 1832 4944'), (4, u'Ricky Marti', u'0.5', u'55 0123 3210'), (5, u'invitada 1', u'0', u'55 0123 LLAMA'), (6, u'invitada 2', u'0', u'55 BUEN AS00')]
>>> l[0]
(2, u'Mario Martinez', u'1', u'55 4944 1832')
>>>

se observa como ‘l’ es una lista y el primer elemento corresponde al primer renglón del resultado

Ahora veamos la forma recomendada de utilizar variables para hacer consultas

Primero, lo que no se recomienda hacer es

>>> val = '1'
>>> c.execute("SELECT * FROM tContact WHERE sex = '%s'" % val)
<sqlite3.Cursor object at 0x14f25e0>
>>> for row in c:
...     print row
...
(1, u'Ricardo Torres', u'1', u'55 1832 4944')
(2, u'Mario Martinez', u'1', u'55 4944 1832')
>>>

La razón es que lo anterior podría permitir inyección de código SQL y por su puesto que nadie quiere eso verdad!! (bueno algunos si lo quicieran pero esto sería tema de otra o otras charlas!)

Por tal motivo, el módulo de Sqlite3 provee de una manera de usar variables en las consultas de forma más segura, de esta forma la anterior consulta quedaría

>>> val = '1'
>>> c.execute("SELECT * FROM tContact WHERE sex = ?", val)
<sqlite3.Cursor object at 0x14f25e0>
>>> for row in c:
...     print row
...
(1, u'Ricardo Torres', u'1', u'55 1832 4944')
(2, u'Mario Martinez', u'1', u'55 4944 1832')
>>>

O en caso de que sea más de un valor, hay que pasarlos como una tupla

>>> vals = ('1','55 4944 1832')
>>> c.execute("SELECT * FROM tContact WHERE sex = ? and movil = ?", vals)
<sqlite3.Cursor object at 0x14f25e0>
>>> for row in c:
...     print row
... 
(2, u'Mario Martinez', u'1', u'55 4944 1832')
>>> 

5.2 Usando el módulo desde un script

A pesar de que usar sqlite desde el intérprete en linea de python es muy flexible y poderoso, hay muchas ocasiones en que una misma tarea se tiene que realizar de forma repetida, por lo tanto combiene colocar todo en un sólo script (o archivo) y ahorrarnos gastar un poco las teclas (aquí he pensado en como sería más felíz una tecla, si cuando la usa uno o cuando la deja descansar, bueno esto podría ser tema para otra charla también!).

Por ejemplo aquí presento un script que me permite encontrar a todos los registros de un sexo en particular y para crearlo propongo usar el editor de texto gedit de la siguiente forma:

$ gedit sexo.py &
$

Y el código que hay que teclear, copiar, tranferir en el editor es el siguiente:

#! /usr/bin/python
# -*- coding: utf-8 -*-

import sqlite3
import sys

basededatos = 'teamparty.sqlite3'


# Es la función recomendada para mostrar la forma correcta de usar este script
def usage():
    print '''Usage: sexo.py N

    Obtiene todos los registros de la base de datos cuyo sexo coincida con N
    
    Donde N - Define un sexo en particular y puede tomar los valores de 0, 1 o
              1.5
    '''

# Función principal que recibe como parámetro la lista de opciones dada en la
# línea de comandos
def main(argv):
    # Validamos que el número de parámetros sea el correcto
    if len(argv) != 1:
        usage()
        sys.exit(1)

    # Se obtiene la conexión y el cursor correcpondiente
    conn = sqlite3.connect(basededatos)
    c = conn.cursor()
    
    # Se obtiene el valor de la opción pasada por el usario
    sex = argv[0]
    c.execute('SELECT * FROM tContact WHERE sex = ?',sex)
    
    # Se imprimen los resultados
    for row in c:
        print row
    
# Esto es para validar si este script se usa de forma independiente o como parte
# de otro módulo
if __name__ == "__main__":
    main(sys.argv[1:])

se guarda el archivo con el nombre sexo.py y se ejecuta de la siguiente manera

la primera ejecución se obtiene la ayuda correspondiente, ya que no se ha pasado ninguna opción, la segunda ejecución corresponde a todos los que tienen sexo igual a 0 y la tercera corresponde a todos los registros que tienen sexo igual a 1.

Sencillo siiii!

5.3 Ejemplo: Exportar datos a CSV

Algo de lo que muchas veces se requiere después de hacer una consulta, es guardar los resultados de alguna manera y unos de los formatos más comúnmente usados son los archivos CSV

Así que vamos a crear un script que lea como parámetro el nombre de un archivo de una base de datos sqlite3 y guarde todo su contenido en archivos csv.

El código fuente de la función sqlite3tocsv() es el siguiente:

# Esta función exporta todo el contenido de una base de datos sqlite3 a archivos
# csv, guardando una tabla por cada archivo.
def sqlite3tocsv(database):
    # Lo primero tener una conexión a la base de datos
    conn = sqlite3.connect(database)
    c = conn.cursor()
    
    # Luego a obtener la lista de tablas
    c.execute('SELECT name FROM sqlite_master WHERE type="table" ORDER BY name')
    
    # Se itera sobre cada tabla
    for table in c:
        filename = database+'_'+table[0]+'.csv'
        
        # Se crea el archivo csv
        foTable = open(filename, 'w')
        cwTable = csv.writer(foTable)
        
        # Se obtienen toda la información de la tabla
        query = 'SELECT * FROM '+table[0]
        c.execute(query)
        
        # Se crea el header con la lista de los campos
        header = []
        for item in c.description:
            header.append(item[0])
        
        # Se guarda el header en el archivo csv
        cwTable.writerow(header)
        
        # Se guardan todos los registros en el archivo csv
        for row in c:
            cwTable.writerow(row)

        # Se cierra el archivo
        foTable.close()

Y una ejecución del script es como sigue

Primero vemos que tengo dos archivos de base de datos sqlite3, luego ejecuto mi script sin parámetros y se muestra la ayuda correspondiente y finalmente ejecuto el script sqlite3tocsv.py pasando como parámetro el nombre de uno de los archivos de base de datos sqlite3y finalmente listo los archivos nuevamente, donde se puede observar un nuevo archivo con terminación csv y cuyo nombre contiene el nombre de la tabla.

Ahora veamos el contenido del archivo

Genial exactamente lo que esperabamos!

Ahora ¿quién se anima a publicar el script completo?

Y esto sería todo por el momento