Nedávno jsem narazil na zajímavý projekt textql, který umožňuje spouštět SQL dotazy nad csv souborem. Samozřejmě mi, stejně jako vám, hned došlo, jak to dělá. Tak se na dvě minutky zamyslete… Taky Vám to vyšlo tak, že načtení csv souboru je banální, a pak se to prostě napere do sqlite databáze, a je hotovo?
Jestli jsem to po zběžném pohledu do kódu textql pochopil dobře, tak nepozná, zda mají data hlavičku, ani nedělá automatickou detekci formátu. My v pythonu máme naštěstí modul csv, který nám s něčím z toho pomůže. Takže:
import csv import sys with open(sys.argv[1], 'rb') as csvfile: sniff_data = csvfile.read(8192) csvfile.seek(0) sniffer = csv.Sniffer() has_header = sniffer.has_header(sniff_data) dialect = sniffer.sniff(sniff_data)
Takže nejprve si přečteme kousek souboru. Uděláme si sniffer. Ten nám na základě souboru řekne, jestli má soubor asi hlavičku, a pak zkusí rozpoznat dialekt – vpodstatě hádá oddělovače sloupců a tak. No a když máme dialekt, tak si uděláme Reader, a načteme:
reader = csv.reader(csvfile, dialect) for row in reader: if table is None: if has_header: table = mk_table_from_header(row) continue else: table = mk_table_dummy_columns(row) insert_row(table, row)
Já moc v sql ani sqlite nejedu, ale jak jsem pochopil, tak sqlite nepotřebuje u sloupců typy – co se tam vloží, to tam bude. Takže v mk_table_from_header si vytáhneme jména sloupců – z hlavičky, a uděláme tabulku, naopak v mk_table_dummy_columns si je prostě očíslujeme jako col1, col2, …
import sqlite3 db_con = sqlite3.connect(":memory:") db_con.text_factory = str def mk_table_from_header(row): columns = set() column_names = [] for i in row: name = get_unused_column_name(safe_column_name(i), columns) columns.add(name) column_names.append(name) cur = db_con.cursor() cur.execute("""create table t1(%s)""" % ", ".join(column_names)) cur.close() return ("t1", column_names) def mk_table_dummy_columns(row): column_names = [ "col_%d" % (i+1) for i in range(len(row)) ] cur = db_con.cursor() cur.execute("""create table t1(%s)""" % ", ".join(column_names)) cur.close() return ("t1", column_names)
Tím insert_row vás ani nebudu obtěžovat.
Ač si autor textql na otázku Is it any good? sám odpovídá Yes, já tento názor moc nesdílím. Nenapadá mě žádný způsob, jak to smysluplně použít. Pro koho to má být? BFU nebude umět použít SQL, programátor asi bude mít s daty nějaký další úmysl, tak proč si to nenapíše celé v pythonu, nebo třeba mém oblíbeném awk?
Proto se dál nebudu zabývat takovýma drobnostma, jako že jestli je hodnota číslo, tak si ji převedeme na číslo, abychom mohli počítat, a tak. Jenom sem dám odkaz na kompletní příklad, kdyby to náhodou někoho zajímalo.
pro podobné účely používám program CSVFix - http://code.google.com/p/csvfix/
Samozrejme to smysl ma, napriklad warehouse timto zpusobem velmi casto cte raw data prave z nejakeho csv a cpe je do L0/L1 tabulek. Oracle db umi i external tables, kde v podstate reknete ze csv soubor je tabulka a pak uz nad ni delate dotazy, agregace atd. Vyvojar dwh se nemusi pachtit s nejakym awk, nemusi mit pristup na system a dokaze si elegantne vytahnout data ktera potrebuje, zpusobem ktery je mu nejblizsi. Otazka spis je jestli to ma smysl pachat nad sqllite :)
Jmenuju se Petr Blahoš. Programuju něco přes 20 let. Tady se snažím psát hlavně o Pythonu, webovém frameworku Pyramid, a občas i o něčem úplně jiném.
Přečteno 19 224×
Přečteno 11 852×
Přečteno 9 344×
Přečteno 8 802×
Přečteno 8 592×