Репликация таблиц базы данных .accdb с помощью python pyodbc

Начинающий пользователь Python здесь. Есть и другие способы добиться этого, но я считаю, что это мой лучший вариант. Я поддерживаю базу данных MS Access 2007 (.accdb), которая используется на планшетных ПК в автономном режиме для сбора данных. Вернувшись в офис, пользователь может повторно подключиться к серверу. Я пытаюсь использовать модуль pyodbc для циклического просмотра таблиц и строк и вставки записей из автономной полевой базы данных в «главную» базу данных сервера. Похоже, что часть скрипта, связанная с выбором, работает над захватом записей из автономной полевой базы данных и помещением их в словарь для последующего использования. Рекомендации, основанные на исходном сообщении, теперь имеют часть вставки, циклически просматривающую словарь и создающую 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() или перед переключением таблиц? Execute умирает, когда заканчивает работу с первой таблицей. Изучаю, но комментарии приветствуются...


person dgj32784    schedule 08.05.2013    source источник


Ответы (1)


ProgrammingError возникает из-за того, что у вас есть как одинарные, так и двойные кавычки вокруг строки 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()
person Matti John    schedule 08.05.2013