5 de julio de 2019

Consultas eficientes sobre ficheros TSV con SQL

Hola,
estos dias está de visita mi colega Valerie y me preguntaba si había alguna manera de seleccionar de manera eficiente filas de un fichero con millones de líneas, en su caso con columnas separadas por tabuladores (TSV). Yo le sugerí una base de datos relacional y como ella escribe sobre todo en python lo hicimos así, con sqlite:

import sqlite3

# local file with data to populate SQL db
data_file = 'data4sql.tab'

# persistent database file to be created, returns a Connection
conn = sqlite3.connect('example.sqlite.db')

# Cursor object to perform SQL commands on that connection
c = conn.cursor()

# create a table as a list of columns and their types (NULL, INTEGER, REAL, TEXT, BLOB)
# NOTE: the columns should match those in data_file
tb_name = 'mytable'
c.execute('CREATE TABLE {tn}\
             (IMG text, scaffold_id text, GC real, length integer, locus_tag text,\
             IMG_gene_id text, gene_type text, gene_start integer, gene_stop integer,\
             gene_length integer, depth real)'.format(tn=tb_name))

with open(data_file) as fin:
    for line in fin:
        cols = line.rstrip().split("\t")

        # make sure empty values are changed to NULL
        cols=[None if x=='' else x for x in cols]
        
        # Insert a row of data
        c.execute("INSERT INTO {tn} VALUES (?,?,?,?,?,?,?,?,?,?,?)".format(tn=tb_name),cols[0:11])

# save (commit) the changes
conn.commit()

# example queries, any valid SELECT SQL can be used
c.execute('SELECT * FROM {tn} WHERE depth >10'.\
        format(tn=tb_name))
for line in c.fetchall():
   print(line)

# close and exit
conn.close()

En realidad esto se debería separar en dos programas, uno para crear la base de datos y otro para hacer consultas sobe ella. El código es sencillo, pero deberás conocer un mínimo de sintaxis SQL para entender cómo crear tablas, con sus tipos, y cómo hacer consultas. Fíjate que los valores perdidos los sustituimos por un objeto None,
saludos,
Bruno y Valerie