2009-03-12 9 views
6

[Edit 2: Plus d'informations et le débogage en réponse ci-dessous ...]Problème Insertion de données dans la base de données MS Access en utilisant ADO via Python

J'écris un script python pour exporter MS Access bases de données dans une série de textes fichiers pour permettre un contrôle de version plus significatif (je sais - pourquoi Access? Pourquoi n'utilise-t-on pas des solutions existantes? Disons simplement que les restrictions ne sont pas de nature technique).

J'ai exporté avec succès le contenu complet et la structure de la base de données en utilisant ADO et ADOX via la bibliothèque comtypes, mais j'obtiens un problème en réimportant les données.

J'exporter le contenu de chaque table dans un fichier texte avec une liste sur chaque ligne, comme ceci:

[-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'] 

Et la fonction suivante pour importer ledit fichier:

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() 

Tout fonctionne correctement sauf que les valeurs numériques (double et int) sont insérées en tant que zéros. Des idées sur si le problème est avec mon code, eval, comtypes, ou ADO? Editer: J'ai corrigé le problème avec l'insertion de nombres - les lancer comme des chaînes (!) Semble résoudre le problème pour les champs doubles et entiers.

Cependant, j'ai maintenant un problème différent qui avait précédemment été obscurci par ce qui précède: le premier champ de chaque ligne est mis à 0 quel que soit le type de données ... Des idées?

Répondre

4

Et trouvé une réponse.

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

doit être:

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

Maintenant, j'ai juste besoin de se pencher sur pourquoi. J'espère juste que cette question sauve quelqu'un d'autre quelques heures ...

+0

Et le reste de la solution était de changer "rs.Fields [i] .Value = data [i]" en "rs.Fields [i] .Value = str (données [i])"? – BIBD

+0

Non, non. Aurait dû le dire explicitement: en ajoutant le dynamic = True a résolu le problème original avec des valeurs numériques, et le problème de suivi avec des résultats variables. Une fois qu'il était en place, rs.Fields [i] .Value = data [i] a bien fonctionné et en fait, il a jeté les nombres car les chaînes ont généré une erreur d'incompatibilité de type. – mavnn

+0

Kewl, je n'étais pas clair sur la réponse. À ce stade, je dirais que votre propre réponse est Acceptée. – BIBD

0

Est-ce que data[i] est traité comme une chaîne? Que se passe-t-il si vous le convertissez en int/double lorsque vous définissez rs.Fields[i].Value?

En outre, que se passe-t-il lorsque vous imprimez le contenu de rs.Fields[i].Value après son réglage?

+0

Voir edit - bizarrement j'avais besoin de lancer spécifiquement de int/double à la chaîne pour le faire fonctionner ... – mavnn

0

Pas encore une réponse complète, mais cela semble être un problème lors de la mise à jour. J'ai ajouté un code supplémentaire de mise au point dans le processus d'insertion qui génère le suivant (exemple d'une seule rangée étant mise à jour):

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] 

La dernière valeur dans chaque ligne « Inserted ... » est le résultat de l'appel rs.Fields [i] .Value avant d'appeler rs.Update(). La ligne "Après ..." affiche les résultats de l'appel de rs.Fields [i] .Value après l'appel de rs.Update().

Ce qui est encore plus ennuyeux, c'est qu'il n'y a pas d'échec fiable. Réexécution exactement le même code sur le même enregistre quelques minutes plus tard générés:

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] 

Comme vous pouvez le voir, les résultats sont fiables jusqu'à ce que vous commettez, puis ... non.

Questions connexes