Conexión con base de datos SQLite en el lenguaje R

El lenguaje de programación R es tremendamente popular entre los matemáticos por estar desarrollado enfocado al análisis estadístico y por ser software libre (licencia GNU/GPL). Y siendo un lenguaje orientado a la estadística la lógica nos dicta que tiene que ser posible conectar con una base de datos.

Por suerte se han desarrollado librerías que sirven como interfaz para trabajar con la mayoría de los sistemas gestores de bases de datos más populares del mercado: SQL-Server, MySQL, PosgreSQL, Oracle y el caso que hoy nos ocupa, SQLite. Principalmente dispones de tres librerías para estas conexiones: ODBC (un standar desarrollado por Microsoft), DBI (basado en DBI de Perl y adaptado de forma nativa para R) y dplyr (otra aproximación nativa profundamente integrada). En este artículo vamos a ver cómo hacerlo con DBI, puesto que es la solución que me han recomendado más programadores de R veteranos.

El primer paso, claro, será instalar los paquetes de la librerías necesarias:

install.packages(c("DBI", "RSQLite"))

Y una vez instalados lo siguiente simplemente es añadir las librerías a nuestro código y configurar una conexión:

library(DBI)
library(RSQLite)

# Definimos el driver
driver <- dbDriver("SQLite")

#realizamos la conexión con dbConnect()
#Esta función recibe como primer parámetro el driver o un objeto
#de conexión ya existente, y como segundo parámetro todos los
#parámetros de conexión que requiere nuestra base de datos.
#SQLite solo necesita la ruta al fichero de la base de datos
#Otros SGBD necesitarán más
archivo_sqlite <- system.file("home/database.sqlite")

conexion <- dbConnect(driver, archivo_sqlite)

#Pdemos ejecutar consultas con dbSendQuery()
#la función recibe el objeto conexión y una consulta SQL.
resultado <- dbSendQuery(conexion, "SELECT * FROM baseDatosEjemplo")

#Para cerrar la conexión con la base de datos
dbDisconnect(conexion)
Anuncios

MySQL: Formateando fechas con DATE_FORMAT()

La función DATE_FORMAT() de MySQL, que fue incorporada en la versió 4.0 del conocido SGBD, nos permite dentro de un select definir el formato de salida de una fecha. La función recibe dos parámetros: una fecha o campo de fecha y una cadena de texto con el formato.

Los siguientes valores pueden ser usados en el formateo de fecha:

%aNombre del día abreviado (Sun a Sat)
%bNombre de mes abreviado (Jan a Dec)
%cMes en formato número (0 a 12)
%DDía del mes en formato numérico seguido de sufijo numeral (1st, 2nd, 3rd, …)
%dDía del mes en formato numérico, forzando dos dígitos  siempre ( de 01 a 31)
%eDía del mes en formato numérico, sin forzar dos dígitos (1 a 31)
%fMicrosegundos (000000 to 999999)
%HHora en formato 24 horas, con dos dígitos
%hHora en formato 12 horas, dos dígitos
%IHora en formato 12 horas, dos dígitos
%iMinutos
%jDía del año (001 a 366)
%kHora en formato 24 horas, sin forzar los dos dígitos
%lHora en formato 12 horas, sin forzar los dos dígitos
%MNombre del mes (January a December)
%mMes en formato numérico, forzando dos dígitos.
%pAM o PM
%rHora en formato 12 horas AM o PM (hh:mm:ss AM/PM)
%SSegundos (00 a 59)
%sSegundos (00 a 59)
%THora en formato 24 horas (hh:mm:ss)
%USemana, tomando el domingo como primer día (00 a 53)
%uSemana, tomando el lunes como primer día (00 to 53)
%VSemana, tomando el domingo como primer día (01 a 53). Usado con %X
%vSemana, tomando el lunes como primer día (01 a 53). Usado con %X
%WNombre del día completo (Sunday to Saturday)
%wNúmero del día en la semana, siendo el domindo 0 y el sábado 6.
%XAño para la semana, tomando el domingo como primer día. Usado con %V
%xAño para la semana, tomando el lunes como primer día. Usado con %V
%YAño en formato de cuatro dígitos
%yAño en formato de dos dígitos

Veamos unos ejemplos si quieres probarlo en casa:

Select DATE_FORMAT("2018-11-20", "%d/%m/%Y"); 
#Pintaría 20/11/2018, el formato europeo
Select DATE_FORMAT("2018-11-20", "%V %X"); 
#Pintaría 46 2018
Select DATE_FORMAT("2018-11-20", "%j-%y"); 
#Pintaría 324-2018
Select DATE_FORMAT("2018-11-20", "%W %d %M"); 
#Pintaría Tuesday 20 November

En el ejemplo le hemos pasado una cadena con una fecha como primer parámetro, pero puedes probar una consulta sobre un campo de una tabla que almacena alguna fecha.

Crear y borrar una vista en SQLite

¿Qué es una vista?

Una vista es una consulta cuyo resultado se presenta como una tabla, puesto que tienen la misma estructura: filas y columnas. La diferencia es que sólo se almacena de ellas la definición y no los datos, que se extraen de las otras tablas de la base de datos. En SQLite la vistas son de solo lectura, de forma que no se pueden ejecutar instrucciones INSERT, DELETE o UPDATE sobre ellas para actualizar las tablas.

¿Cómo creo una vista en SQLite?

Para crear una vista en SQLite tenemos la instrucción CREATE VIEW. Tendremos que asignar un nombre a la vista que creamos y ejecutar una consulta que nos devuelva los datos que formarán nuestra vista. La sintaxis sería:

CREATE VIEW Vista_Nueva 
AS 
SELECT
	t1.Id,
        t1.Campo1,
        t2.Campo1 as Campo2
FROM
	tabla t1
INNER JOIN tabla2 t2 ON t1.IdEnTabla2 = t2.Id;

Vamos a poner como ejemplo que tenemos una tabla con variedades de quesos, otra con países y otra con tipos de leche. Y queremos una vista que nos muestre de qué país y con qué tipo de leche está hecho cada queso. Pues podríamos sacarlo con una consulta así:

CREATE VIEW v_QuesosDetallada 
AS 
SELECT
	q.Id,
        q.Nombre,
        p.Nombre as Pais,
        l.Descripcion as TipoLeche
FROM
	Quesos q
INNER JOIN paises p ON q.IdPais = p.Id
INNER JOIN leches l ON q.IdTipoLeche = l.Id;

¿Cómo borro una vista?

Para eliminar una vista en SQLite tenemos la instruccion DROP VIEW, que iría seguida del nombre de la tabla. Siguiendo con el ejemplo de arriba, para borrar la vista v_QuesosDetallada tendríamos que ejecutar la siguiente instrucción:

DROP VIEW v_QuesosDetallada;

De esta forma eliminaríamos la vista de nuestra base de datos.

Si intentamos crear una vista con un nombre que ya existe o si intentamos borrar una que no existe recibiremos un mensaje de error. Por tanto es interesante asegurarse utilizando IF NOT EXISTS a la hora de crear e IF EXISTS a la de borrar.

Calcular la edad a partir de una fecha en SQLite.

Otra entrada sobre SQLite, vendrán algunas más ya que he tenido que estudiar un poco sobre ello para utilizarlo en una aplicación. Y ya que nos ponemos con consultas y truquitos vamos con el siguiente: ¿Cómo calculamos la edad a partir de una fecha? Ya lo vimos en el pasado con SQL-Server, con MySQL y con PostgreSQL, incluso fuera del tema de las bases de datos también lo hicimos con Javascript.

Supongamos que tenemos una base de datos Usuarios con un campo FechaNacimiento donde almacenamos, como te puedes imaginar, una fecha. Para calcular la edad a día de hoy podemos hacer dos cosas:

La primera es el clásico “Restamos un año a otro y luego si el día del cumpleaños todavía no llegó restamos uno año más“, que podríamos expresar así en una consulta:

SELECT (strftime('%Y', 'now') - strftime('%Y', FechaNacimiento )) - (strftime('%m-%d', 'now') < strftime('%m-%d', FechaNacimiento )) from Usuarios;

Como ves, en primer lugar extraemos los años de las dos fechas y los restamos. En la segunda resta añadimos la compración entre mes y día actual y mes y día de la fecha, dicha evaluación devolverá 1 si es anterior y 0 si no lo es, de esta forma resta 1 en ese caso.

Otra solución, convertir ambas fechas a un formato numérico y restarlas, y después convertir a un formato de número entero:

Select cast(strftime('%Y.%m%d', 'now') - strftime('%Y.%m%d', FechaNacimiento ) as int) from Usuarios;

Utilizar SQLiteStudio en Ubuntu

SQLiteStudio es un software libre multiplataforma que nos proporciona una interfaz gráfica para trabajar con bases de datos SQLite. Existen versiones para Linux, Windows y MacOS.

En el siguiente enlace puedes entrar a la página de descargas de SQLiteStudio, donde hay dos opciones: un instalador y un paquete .tar.xz con una versión portable del programa.

Durante las pruebas he tenido problemas con la versión con instalador en una máquina con Xunbutu, pero la versión portable ha funcionado sin problemas. Basta con descargarla y desempaquetarla:

SQLite Studio Descarga

Descomprimir SQLitestudio

Una vez desempaquetado buscamos el programa y lo ejecutamos. En la primera ejecución nos pedirá que definamos el idioma:

Ejecutable sqlitestudio

Y listo, ya está funcionando SQLiteStudio en tu equipo:

SQLite Xubuntu

Calcular la mediana en SQL-Server

Como no me apetece meterme en una discusión infructuosa con un individuo *troll ultraderechista sexualmente frustrado* voy a aprovechar la hora de comer en el trabajo para comentaros cómo podemos calcular la mediana de una serie de números en SQL-Server. Ya vimos no hace mucho el significado de este término y también cómo podemos calcularlo en Libre Office Calc.

Si vamos a trabajar con SQL-Server 2012 o superior la función PERCENTILE_DISC() nos servirá, sin tener que hacer nada más. Es una función que calcula un percentil concreto para una serie de valores ordenados de un conjunto de filas, y su sintaxis es:

PERCENTILE_DISC ( número ) WITHIN GROUP ( ORDER BY exp_ordenación [ ASC | DESC ] )
OVER ( [ partido_por ] )

Aquí os copio sus argumentos de la web de documentación de Microsoft directamente, donde también tenéis ejemplos de código para SQL-Server y para Azure:

  • número :El percentil que se va a calcular. El valor debe estar entre 0,0 y 1,0.
  • WITHIN GROUP ( ORDER BY exp_ordenación[ ASC | DESC ]):Especifica una lista de valores para ordenar y cuyo percentil se va a calcular. Solo se permite una exp_ordenación. El criterio de ordenación predeterminado es ascendente. La lista de valores puede ser de cualquiera de los tipos de datos válidos para la operación de ordenación.
  • OVER ( partido_por ):Divide el conjunto de resultados generado por la cláusula FROM en particiones a las que se aplica la función de percentil. Para más información, vea Cláusula OVER (Transact-SQL). Las cláusulas y no se pueden especificar en una función PERCENTILE_DISC.

De esta forma PERCENTILE_DISC(0.5) calculará la mediana del cojunto de filas que estamos analizando.

Pero ¿qué pasa si trabajamos con una versión anterior a SQL-Server 2012? Te parecerá algo prehistórico, pero en muchos sitios sigue funcionando SQL-Server 2008 o 2005. ¿Cómo lo hago ahí donde no dispongo de la función PERCENTILE_DISC()?

Bueno, ahí he hecho una solución un poco picapedrera, porque según el conjunto de datos que tengamos las hay bastante mejores. Esta realmente consume muchos recursos, pero por otra parte es universal. Si la tabla cuenta con una columna de Identidad la cosa puede ser más eficiente:

Básicamente he usado una tabla llamada Actividades, donde hay una columna numérica llamada Importe. Para calcular la mediana de este importe vamos a sacar los dos valores centrales dividiendo las filas en dos mitades, ordenando una de forma descendente y otra ascendente. Tras eso los sumamos y hacemos la media de la suma.

Select ((
    Select Top 1 Importe
    From   (
                    Select  Top 50 Percent Importe
                    From    Actividades
                    Where   Importe Is NOT NULL
                    Order By Importe
                    ) As A
    Order By Importe DESC) + 
    (
    Select Top 1 Importe
    From   (
                    Select  Top 50 Percent Importe
                    From    Actividades
                    Where   Importe Is NOT NULL
                    Order By Importe DESC
                    ) As A
    Order By Importe Asc)) / 2 as MedianaImportes

SQL-Server: Reiniciar el valor de una columna de identidad

Imaginemos que hemos borrado todos los registros de una tabla, en SQL-Server, que tenía definida una columna de identidad como clave primaria. Ahora queremos que las nuevas inserciones no comiencen desde el último Id borrado sino desde el principio ¿Cómo lo hacemos? Es muy simple:

DBCC CHECKIDENT ('NuestraTabla', RESEED, 1);

Vale, pero ¿y si no hemos borrado todos los valores sino, por ejemplo, solo un 20% de ellos? ¿Cómo hacemos para que empiece desde el valor máximo? Pues con este método lo haríamos:

DBCC CHECKIDENT ('NuestraTabla', RESEED, 1);
DBCC CHECKIDENT ('NuestraTabla', RESEED);

De esta forma le ponemos el valor a 1 y luego el segundo comando pondrá automáticamente el valor máximo de la tabla.

¿Y si hemos metido manualmente un valor en la Id, desactivando el chequeo de identidad para la inserción, mayor que el que tocaba y queremos que siga desde ahí?

DBCC CHECKIDENT ('NuestraTabla', RESEED);

Pues de nuevo invocamos la función sin ningún valor definido.