Transacción SQLite para importar CSV

Soy muy nuevo en python y he estado trabajando en mi raspberry pi para poner en marcha un script para importar millones de registros de datos de sensores a sqlite. Quiero hacer esto en las transacciones para que el proceso sea más eficiente. Estoy tratando de dividir las transacciones en partes de 10k como se hace aquí: Python CSV to SQLite

Hasta ahora tengo

import csv, sqlite3, time def chunks(data, rows=10000): for i in range (0, len(data), rows): yield data[i:i+rows] if __name__ == "__main__": t = time.time() con = sqlite3.connect('test.db') cur = con.cursor() cur.execute("DROP TABLE IF EXISTS sensor;") cur.execute("CREATE TABLE sensor(key INT, reading REAL);") filename = 'dummy.csv' reader = csv.reader(open(filename,"r")) divdata = chunks(reader) for chunk in divdata: cur.execute('BEGIN TRANSACTION') for col1, col2 in chunk: cur.execute('INSERT INTO sensor (key, reading) VALUES (?, ?)', (col1, col2)) con.execute('COMMIT') 

Estoy recibiendo el siguiente error en Python 3.2.3:

 Traceback (most recent call last): File "/home/pi/test1.py", line 20, in  for chunk in divdata: File "/home/pi/test1.py", line 4, in chunks for i in range (0, len(data), rows): TypeError: object of type '_csv.reader' has no len() 

Obviamente estoy arruinando la parte de los trozos en algún lugar, ya que todo (inserción básica) funciona bien sin los trozos y la transacción. Cualquier ayuda apreciada.

Tu SQL se ve bien. Sin embargo, veo un problema con su lector de CSV: no es compatible con len() la forma en que lo utiliza en chunks() .

Puede usar el más típico for row in data bucle de for row in data , o usar una de las técnicas descritas en este hilo si necesita dividir el archivo en trozos.

Hubo dos problemas en el fragmento de código en la búsqueda:

  1. El lector en la llamada a los chunks debe haberse incluido en la list()
  2. el ‘commit’ debería haber estado usando el método commit() la conexión

Ver el código fijo:

 import csv, sqlite3, time def chunks(data, rows=10000): for i in range (0, len(data), rows): yield data[i:i+rows] if __name__ == "__main__": t = time.time() con = sqlite3.connect('test.db') cur = con.cursor() cur.execute("DROP TABLE IF EXISTS sensor;") cur.execute("CREATE TABLE sensor(key INT, reading REAL);") filename = 'dummy.csv' reader = csv.reader(open(filename,"r")) divdata = chunks(list(reader)) for chunk in divdata: cur.execute('BEGIN TRANSACTION') for col1, col2 in chunk: cur.execute('INSERT INTO sensor (key, reading) VALUES (?, ?)', (col1, col2)) con.commit() 

El problema es que el objeto que obtiene del método csv.reader no admite la función len() . De hecho, este lector de CSV lee solo cuando se le indica que lo haga, y como tal, no sabe cuántos registros hay en el archivo.

Como tal, necesita actualizar el método de chunks para tratar de no saber la cantidad de cosas que se van a fragmentar. Reemplace esa función con esto:

 def chunks(data, n=10000): buffer = [None] * n idx = 0 for record in data: buffer[idx] = record idx += 1 if idx == n: yield buffer buffer = [None] * n idx = 0 if idx > 0: yield buffer[:idx] 

Lo que esto hace es: sigue recuperando registros de su archivo siempre que haya registros para recuperar, y cada n filas, emite una lista de n registros. Por ejemplo:

 >>> for c in chunks(range(10), 3): ... print(c) ... [0, 1, 2] [3, 4, 5] [6, 7, 8] [9]