A causa della potenza di SQLAlchemy, lo sto utilizzando anche su un progetto. Il suo potere deriva dal modo orientato agli oggetti di "parlare" a un database invece di istruzioni SQL hardcoded che possono essere difficili da gestire. Per non parlare, è anche molto più veloce.
Per rispondere alla tua domanda senza mezzi termini, si! Memorizzare i dati da un CSV in un database usando SQLAlchemy è un gioco da ragazzi. Ecco un esempio di lavoro completo (io ho usato SQLAlchemy 1.0.6 e Python 2.7.6):
from numpy import genfromtxt
from time import time
from datetime import datetime
from sqlalchemy import Column, Integer, Float, Date
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
def Load_Data(file_name):
data = genfromtxt(file_name, delimiter=',', skip_header=1, converters={0: lambda s: str(s)})
return data.tolist()
Base = declarative_base()
class Price_History(Base):
#Tell SQLAlchemy what the table name is and if there's any table-specific arguments it should know about
__tablename__ = 'Price_History'
__table_args__ = {'sqlite_autoincrement': True}
#tell SQLAlchemy the name of column and its attributes:
id = Column(Integer, primary_key=True, nullable=False)
date = Column(Date)
opn = Column(Float)
hi = Column(Float)
lo = Column(Float)
close = Column(Float)
vol = Column(Float)
if __name__ == "__main__":
t = time()
#Create the database
engine = create_engine('sqlite:///csv_test.db')
Base.metadata.create_all(engine)
#Create the session
session = sessionmaker()
session.configure(bind=engine)
s = session()
try:
file_name = "t.csv" #sample CSV file used: http://www.google.com/finance/historical?q=NYSE%3AT&ei=W4ikVam8LYWjmAGjhoHACw&output=csv
data = Load_Data(file_name)
for i in data:
record = Price_History(**{
'date' : datetime.strptime(i[0], '%d-%b-%y').date(),
'opn' : i[1],
'hi' : i[2],
'lo' : i[3],
'close' : i[4],
'vol' : i[5]
})
s.add(record) #Add all the records
s.commit() #Attempt to commit all the records
except:
s.rollback() #Rollback the changes on error
finally:
s.close() #Close the connection
print "Time elapsed: " + str(time() - t) + " s." #0.091s
(Nota: questo non è necessariamente il modo "migliore" per fare questo, ma credo che questo formato è molto leggibile per un principiante, è anche molto veloce: 0,091 per 251 record inseriti!)
Penso che se lo si analizzi riga per riga, vedrai che è un gioco da ragazzi. Si noti la mancanza di istruzioni SQL - evviva! Mi sono anche preso la libertà di usare numpy per caricare il contenuto CSV in due righe, ma se lo desideri puoi farlo senza di esso.
Se si volesse confrontare con il modo tradizionale di farlo, ecco un esempio completo per la lavorazione di riferimento:
import sqlite3
import time
from numpy import genfromtxt
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
def Create_DB(db):
#Create DB and format it as needed
with sqlite3.connect(db) as conn:
conn.row_factory = dict_factory
conn.text_factory = str
cursor = conn.cursor()
cursor.execute("CREATE TABLE [Price_History] ([id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE, [date] DATE, [opn] FLOAT, [hi] FLOAT, [lo] FLOAT, [close] FLOAT, [vol] INTEGER);")
def Add_Record(db, data):
#Insert record into table
with sqlite3.connect(db) as conn:
conn.row_factory = dict_factory
conn.text_factory = str
cursor = conn.cursor()
cursor.execute("INSERT INTO Price_History({cols}) VALUES({vals});".format(cols = str(data.keys()).strip('[]'),
vals=str([data[i] for i in data]).strip('[]')
))
def Load_Data(file_name):
data = genfromtxt(file_name, delimiter=',', skiprows=1, converters={0: lambda s: str(s)})
return data.tolist()
if __name__ == "__main__":
t = time.time()
db = 'csv_test_sql.db' #Database filename
file_name = "t.csv" #sample CSV file used: http://www.google.com/finance/historical?q=NYSE%3AT&ei=W4ikVam8LYWjmAGjhoHACw&output=csv
data = Load_Data(file_name) #Get data from CSV
Create_DB(db) #Create DB
#For every record, format and insert to table
for i in data:
record = {
'date' : i[0],
'opn' : i[1],
'hi' : i[2],
'lo' : i[3],
'close' : i[4],
'vol' : i[5]
}
Add_Record(db, record)
print "Time elapsed: " + str(time.time() - t) + " s." #3.604s
(Nota: anche nel modo "vecchio", questo non è affatto il il modo migliore per farlo, ma è molto leggibile e una traduzione "1-a-1" da SQLAlchemy way vs. "old" way.)
Si noti le istruzioni SQL: uno per creare la tabella, il altro per inserire record. Inoltre, si noti che è un po 'più ingombrante mantenere lunghe stringhe SQL rispetto a una semplice aggiunta di attributi di classe. Mi piace SQLAlchemy finora?
Come per la richiesta chiave esterna, ovviamente. SQLAlchemy ha il potere di fare anche questo. Ecco un esempio di come un attributo di classe sarà simile con un incarico chiave esterna (assumendo che la classe ForeignKey
inoltre è stato importato dal modulo sqlalchemy
):
class Asset_Analysis(Base):
#Tell SQLAlchemy what the table name is and if there's any table-specific arguments it should know about
__tablename__ = 'Asset_Analysis'
__table_args__ = {'sqlite_autoincrement': True}
#tell SQLAlchemy the name of column and its attributes:
id = Column(Integer, primary_key=True, nullable=False)
fid = Column(Integer, ForeignKey('Price_History.id'))
che indica la colonna "FID" come chiave esterna per Colonna id di Price_History.
Spero che questo aiuti!
Prenderò il vecchio modo con lo sql. – javadba
Questo è un codice utile, ma sarebbe utile se il file di dati fosse incluso nell'esempio. Quindi sarebbe veramente autonomo. –
Non ho verificato il motivo per cui ciò sta accadendo, ma 'genfromtxt' restituisce l'errore:' genfromtxt() ha ottenuto un argomento di parole chiave inaspettato 'skiprows''. Numpy è '1.12.1-3' (Debian 9.0). –