使用 pyodbc 和 pandas 将 CSV 加载到 .mdb

1 python csv ms-access pyodbc pandas

背景故事: 我从事财务工作(不是开发人员,因此非常感谢帮助),我的部门目前严重依赖 excel 和 vba 来尽可能多地自动化我们的任务。该公司刚刚验证了一个 python 发行版,我们现在可以使用它,所以我只是想尝试一下。

挑战: 我的第一个挑战是将 CSV 文件加载到 MSAcess 数据库中(因为并非所有人都精通技术,可以纯粹使用开发工具和数据库进行工作,因此需要让每个人都轻松完成工作)。

我可以在互联网上找到零碎的不同 ppl 代码,我可以将它们放在一起,它可以工作,但结果却变成了弗兰肯斯坦。

它在做什么以及为什么:

  1. 将 CSV 加载到变量
  2. 去掉第一行(因为源文件不是真正的 CSV,文件开头有垃圾行)
  3. 导出到临时驱动器中的 CSV(因为无法弄清楚如何从变量加载到熊猫)
  4. 使用 panda 将 CSV 加载到 SQLite(因为 panda 能够推断每列的数据类型)
  5. 将“创建表”语句导出到变量
  6. 使用 pyodbc 在 .mdb 文件中创建表
  7. 将数据逐行加载到 .mdb 表中(非常慢)

TL;DR:
当前的代码是不同代码的拼凑而成,它既丑陋又缓慢,您会更改什么以使其更有效/优化它?

目标是拥有一个将 CSV 加载到 .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()
Run Code Online (Sandbox Code Playgroud)

谢谢,因为你们比我好得多,希望得到任何建议。

Par*_*ait 5

MS Access 可以直接查询 CSV 文件并运行生成表查询以生成结果表。但是,需要进行一些清洁才能清除垃圾行。下面打开两个文件,一个用于读取,另一个用于写入。假设垃圾在 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 
Run Code Online (Sandbox Code Playgroud)

原始 CSV

原始 CSV 文件

清洁 CSV

清洁 CSV

MS 访问表

MS 访问表

注意 Access 可以推断列类型,例如第一列中的日期。