Проблема Вставка данных в базу данных MS Access с использованием ADO через Python

[Изменить 2: дополнительная информация и отладка в ответе ниже...]

Я пишу скрипт на Python для экспорта баз данных MS Access в серию текстовых файлов, чтобы обеспечить более значимый контроль версий (я знаю — почему Access? Почему я не использую существующие решения? Скажем так, ограничения не технический характер).

Я успешно экспортировал все содержимое и структуру базы данных с помощью ADO и ADOX через библиотеку comtypes, но у меня возникла проблема с повторным импортом данных.

Я экспортирую содержимое каждой таблицы в текстовый файл со списком в каждой строке, например:

[-9, u'No reply']
[1, u'My home is as clean and comfortable as I want']
[2, u'My home could be more clean or comfortable than it is']
[3, u'My home is not at all clean or comfortable']

И следующая функция для импорта указанного файла:

import os
import sys
import datetime
import comtypes.client as client
from ADOconsts import *
from access_consts import *

class Db:
    def create_table_contents(self, verbosity = 0):
        conn = client.CreateObject("ADODB.Connection")
        rs = client.CreateObject("ADODB.Recordset")
        conn.ConnectionString = self.new_con_string
        conn.Open()
        for fname in os.listdir(self.file_path):
            if fname.startswith("Table_"):
                tname = fname[6:-4]
                if verbosity > 0:
                    print "Filling table %s." % tname
                conn.Execute("DELETE * FROM [%s];" % tname)
                rs.Open("SELECT * FROM [%s];" % tname, conn,
                        adOpenDynamic, adLockOptimistic)
                f = open(self.file_path + os.path.sep + fname, "r")
                data = f.readline()
                print repr(data)
                while data != '':
                    data = eval(data.strip())
                    print data[0]
                    print rs.Fields.Count
                    rs.AddNew()
                    for i in range(rs.Fields.Count):
                        if verbosity > 1:
                            print "Into field %s (type %s) insert value %s." % (
                                rs.Fields[i].Name, str(rs.Fields[i].Type),
                                data[i])
                        rs.Fields[i].Value = data[i]
                    data = f.readline()
                    print repr(data)
                    rs.Update()
                rs.Close()
        conn.Close()

Все работает нормально, за исключением того, что числовые значения (double и int) вставляются как нули. Любые идеи о том, связана ли проблема с моим кодом, eval, comtypes или ADO?

Редактировать: я исправил проблему со вставкой чисел - преобразование их в строки (!), похоже, решает проблему как для двойных, так и для целых полей.

Однако теперь у меня другая проблема, которая ранее была скрыта вышеизложенным: первое поле в каждой строке устанавливается равным 0 независимо от типа данных... Есть идеи?


person mavnn    schedule 12.03.2009    source источник


Ответы (3)


И нашел ответ.

    rs = client.CreateObject("ADODB.Recordset")

Должно быть:

    rs = client.CreateObject("ADODB.Recordset", dynamic=True)

Теперь мне просто нужно разобраться, почему. Просто надеюсь, что этот вопрос сэкономит кому-то еще несколько часов...

person mavnn    schedule 12.03.2009
comment
И оставшаяся часть решения заключалась в том, чтобы изменить rs.Fields[i].Value = data[i] на rs.Fields[i].Value = str(data[i])? - person BIBD; 12.03.2009
comment
Нет нет. Надо было прямо сказать: добавление dynamic=True решило как исходную проблему с числовыми значениями, так и последующую проблему с переменными результатами. Как только это было на месте, rs.Fields[i].Value = data[i] работало нормально, и на самом деле преобразование чисел в строки вызывало ошибку несоответствия типов. - person mavnn; 12.03.2009
comment
Кьюл, я не совсем ясно ответил. На этом этапе я бы сказал, пометьте свой ответ как принятый. - person BIBD; 12.03.2009

Обрабатывается ли data[i] как строка? Что произойдет, если вы специально примените его как int/double при установке rs.Fields[i].Value?

Кроме того, что происходит, когда вы распечатываете содержимое rs.Fields[i].Value после его установки?

person BIBD    schedule 12.03.2009
comment
Смотрите редактирование - как ни странно, мне нужно было специально преобразовать int/double в строку, чтобы заставить его работать... - person mavnn; 12.03.2009

Еще не полный ответ, но, похоже, это проблема во время обновления. Я добавил дополнительный код отладки в процесс вставки, который генерирует следующее (пример обновления одной строки):

Inserted into field ID (type 3) insert value 1, field value now 1.
Inserted into field TextField (type 202) insert value u'Blah', field value now Blah.
Inserted into field Numbers (type 5) insert value 55.0, field value now 55.0.
After update: [0, u'Blah', 55.0]

Последнее значение в каждой строке «Inserted...» является результатом вызова rs.Fields[i].Value перед вызовом rs.Update(). В строке «После...» показаны результаты вызова rs.Fields[i].Value после вызова rs.Update().

Что еще более раздражает, так это то, что он не надежно выходит из строя. Повторный запуск того же кода на тех же записях через несколько минут сгенерировал:

Inserted into field ID (type 3) insert value 1, field value now 1.
Inserted into field TextField (type 202) insert value u'Blah', field value now Blah.
Inserted into field Numbers (type 5) insert value 55.0, field value now 55.0.
After update: [1, u'Blah', 2.0]

Как видите, результаты надежны до тех пор, пока вы их не зафиксируете, тогда... нет.

person mavnn    schedule 12.03.2009