2017-01-02 93 views
0

背景故事: 我在金融方面工作(不是开发人员,所以非常感谢帮助),我的部门目前主要依靠excel和vba来尽可能地自动化我们的任务。该公司刚刚验证了python发行版,现在我们可以使用它了,所以我只是想尝试一下。使用pyodbc和熊猫将CSV加载到.mdb

挑战: 我的第一个挑战是加载一个CSV文件导入到一个MSAcess数据库(因为不是所有的人都高科技萨维足以纯粹工作中使用开发工具和数据块,因此需要让一切变得简单为大家) 。

我可以在互联网上找到不同的ppl代码,我可以放在一起,它工作,但它变成了科学怪人。

它在做什么以及为什么:

  1. 负载CSV可变
  2. 地带出第一行(由于源文件是不是真的一个CSV,有垃圾排在文件的开始)
  3. 导出到临时驱动器中的CSV(因为无法弄清楚如何从变量加载到熊猫)
  4. 使用熊猫将CSV加载到SQLite(因为熊猫能够推断每列的数据类型)
  5. 导出 “CREATE TABLE” 语句来可变
  6. 使用pyodbc
  7. 加载数据按行的.mdb表行创建.mdb文件表(它很慢)

TL; DR:
当前代码是不同代码拼凑而成的,它很丑,很慢,你会改变什么来提高效率/优化它?

目标是将代码加载到.mdb,可能使用正确的数据类型来创建表。

import csv 
import pyodbc 
import pandas 
import pandas.io.sql 
import sqlite3 
import tempfile 
import time 
import string 


def load_csv_to_access(access_path, table_name, csv_path, skip_rows): 


# open CSV file, load to a variable, output to a temp file excluding first non csv rows 
# 
filename = csv_path 
csv_file = open(filename) 
txt = "" 
for index, line in enumerate(csv_file, start=0): #Skip first rows 
    if index > skip_rows: 
     txt += line 
csv_file.close() 
temp_filename = time.strftime("%y%m%d%H%M%S") + '.csv' 
temp_filepath = tempfile.gettempdir() + '\\' + temp_filename 
file = open(temp_filepath, 'w+') 
file.write(txt) # create temp csv 
file.close() 
print "1: temp file created: " + temp_filepath 

# Use panda and SQLite to infer data type of CSV fields 
# 
df = pandas.read_csv(temp_filepath, delimiter=';', index_col=0, engine='python') 
df.columns = df.columns.str.replace(' ', '_') 
# connect to in-memory database for testing; replace `:memory:` w/ file path 
con = sqlite3.connect('db.sqlite') 
df.to_sql(table_name, con, if_exists='replace') 
sqlite_query_string = "SELECT sql FROM sqlite_master where name = '" + table_name + "'" 
create_table_tuple = con.execute(sqlite_query_string).fetchone() 
con.close() 
create_table_string = create_table_tuple[0] 
print "2: Data type inferred" 

#Connect to AccessDB and load temp CSV 
# 
access_string = "DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=" + access_path + "; Provider=MSDASQL;" 
print access_string 
con = pyodbc.connect(access_string) 
cur = con.cursor() 
cur.execute(create_table_string) 
con.commit() 
print "3: MS Access table created: " + table_name 

print "4: Loading data rows:" 
with open(temp_filepath, 'r') as f: 
    reader = csv.reader(f, delimiter=';') 
    columns = next(reader) 
    query = "insert into " + table_name + "({0}) values ({1})" 
    query = query.format(','.join(columns).replace(' ', '_'), ','.join(
     '?' * len(columns))) #Create insert query (replace empty space by underscore to avoid db issues) 
    for index, data in enumerate(reader, start=0): 
     cur.execute(query, data) #Insert row by row 
     print index # For debugging 
    cur.commit() 
con.close() 

谢谢你,因为你们比我好得多,我会很感激任何建议。

+1

请访问http://codereview.stackexchange.com/ – Gustav

+0

访问此链接也可以推断列类型。您是否在使用熊猫,因为它做得更好,或者仅仅因为这是您在搜索时发现的东西? –

+0

@GordThompson因为这是我在搜索时可以找到的,并不需要从Access执行或甚至打开它。我的计划是有一个函数可以解析不同的CSV文件并将其加载到.mdb文件中,而无需从Access中执行,因此我可以在夜间自动运行脚本,稍后可以通过阅读一个包含csv文件列表以及对应的.mdb和表名的表。上面的代码有用,但速度很慢,特别是它为每行运行插入查询的最后部分。 – ddensa

回答

1

MS Access可以直接查询CSV文件并运行Make-Table Query来生成结果表。但是,需要一些清洁来清除垃圾行。下面打开两个文件一个阅读和其他写作。假设垃圾是在CSV的第一列中,if逻辑写入具有在第二列中的某些数据的任何线(根据需要进行调整):

import os 
import csv 
import pyodbc 

# TEXT FILE CLEAN 
with open('C:\Path\To\Raw.csv', 'r') as reader, open('C:\Path\To\Clean.csv', 'w') as writer: 
    read_csv = csv.reader(reader); write_csv = csv.writer(writer, lineterminator='\n') 

    for line in read_csv: 
     if len(line[1]) > 0:    
      write_csv.writerow(line) 

# DATABASE CONNECTION 
access_path = "C:\Path\To\Access\\DB.mdb" 
con = pyodbc.connect("DRIVER={{Microsoft Access Driver (*.mdb, *.accdb)}};DBQ={};" \ 
        .format(access_path)) 

# RUN QUERY 
strSQL = "SELECT * INTO [TableName] FROM [text;HDR=Yes;FMT=Delimited(,);" + \ 
     "Database=C:\Path\To\Folder].Clean.csv;"  
cur = con.cursor() 
cur.execute(strSQL) 
con.commit() 

con.close()       # CLOSE CONNECTION 
os.remove('C\Path\To\Clean.csv')  # DELETE CLEAN TEMP 

原始CSV

Raw CSV File

清洁CSV

Clean CSV

MS访问表

MS Access Table

通知访问可以推断列类型,如在第一列中的日期。

+0

Awsome!谢谢! – ddensa