使用python pyodbc复制.accdb数据库表

时间:2013-05-08 21:10:12

标签: python ms-access-2007 database-replication pyodbc

新手python用户在这里。还有其他方法可以达到这个目的,但我相信这是我最好的选择。我维护一个MS Access 2007数据库(.accdb),该数据库在现场的脱机TabletPC上用于收集数据。当返回办公室时,用户可以重新连接到服务器。我正在尝试利用pyodbc模块遍历表和行,并将记录从脱机字段数据库插入服务器“master”数据库。脚本的选择部分似乎正在捕获离线字段数据库中的记录,并将它们放入字典中供以后使用。基于原始帖子的建议现在具有循环遍历字典的插入部分并创建用于插入记录的基于参数的sql。但是,在将两个记录插入循环中的第一个表后,代码将引发以下错误。下一个sql字符串用于下一个表 - 因此所有记录都正确地插入到第一个表中,并且在移动到下一个表时发生错误。

Error: ('HY010', '[HY010] [Microsoft][ODBC Driver Manager] Function sequence error (0) (SQLFetch)')

我在这里阅读了错误信息,但不知道该怎么做:http://msdn.microsoft.com/en-us/library/windows/desktop/ms712424(v=vs.85).aspx

import pyodbc

otherDbaseDict = {}

connOtherDbase = pyodbc.connect(("Driver={Microsoft Access Driver (*.mdb, *.accdb)};"
                                 "DBQ=C:\\other.accdb;"))
otherDbaseTables = connOtherDbase.cursor().tables()

counter = 0

for tblOther in otherDbaseTables:
    if tblOther.table_name.startswith("tbl"): #ignores MS sys tables
        nameOther = tblOther.table_name
        cursor = connOtherDbase.cursor()
        selectSQL = 'SELECT * FROM {}'.format(nameOther) #generate SQL select syntax
        cursor.execute(selectSQL)
        rows = cursor.fetchall()
        for row in rows:
            counter = counter + 1 #counter digit used to create unique key, since table names repeat
            otherDbaseDict.update({nameOther+str(counter):row})

connMainDbase = pyodbc.connect(("Driver={Microsoft Access Driver (*.mdb, *.accdb)};"
                                "DBQ=C:\\main.accdb;"))
mainDbaseTables = connMainDbase.cursor().tables()

#beargle2
for tblMain in mainDbaseTables:
    if tblMain.table_name.startswith("tbl"):
        nameMain = tblMain.table_name
        # get all column names with list comprehension
        columns = [row.column_name for row in cursor.columns(table=nameMain)]
        for k, v in otherDbaseDict.iteritems():
            if nameMain in k:
                # build dynamic sql
                sql = 'INSERT into {0}({1}) values ({2})'
                # add question mark placeholders, one for each column
                # value to insert
                sql = sql.format(nameMain, ','.join(columns),
                                 ','.join(len(columns) * '?'))
                #print sql
                cursor = connMainDbase.cursor()
                # execute parameterized insert
                cursor.execute(sql, v)
                connMainDbase.commit()

有关如何协调错误的指示?只是在想,这是游标问题吗?我是否需要“重置/刷新”或在每个connMainDbase.commit()之后或切换表之前调用它?一旦完成第一个表,就执行死亡。调查,但评论欢迎...

1 个答案:

答案 0 :(得分:1)

编程错误正在发生,因为insertSQL字符串周围有单引号和双引号。

您只有一个字段的原因是您仍然在为列表添加字段名称的for循环块内。在构造insertSQL字符串之前需要取消注释,所以最后几行应该是:

for row in cursor.columns(table=nameMain):
    fieldName = str(row.column_name)
    fields.append(fieldName)
insertSQL = 'INSERT into {0}({1}) values ({2})'.format(nameMain,fields,v)
cursor.execute(insertSQL)
connMainDbase.commit()

但是,这仍然不能为您提供有效的SQL,因为您的字段名称在单引号和方括号内,并且您的值周围有双括号。我认为解决这个问题的最简单方法是转换列表和放大器。首先是字符串元组:

insertSQL = 'INSERT into {0}({1}) values ({2})'.format(nameMain,', '.join(fields),', '.join(v))

最后,最佳做法是将您的值作为参数传递给execute方法,以便您使用参数化查询(在您的用例中可能无关紧要,但您也可以遵循最佳做法无论如何)。要做到这一点你需要吗?代替需要添加到查询中的每个值,您可以将' ,'.join(v)替换为' ,'.join('?'*len(v))并将v元组作为第二个参数传递给execute

你最终应该:

for row in cursor.columns(table=nameMain):
    fieldName = str(row.column_name)
    fields.append(fieldName)
    insertSQL = 'INSERT into {0}({1}) values ({2})'.format(nameMain,', '.join(fields),', '.join('?'*len(v)))
cursor.execute(insertSQL, v)
connMainDbase.commit()