0

初心者の python ユーザーはこちら。これを達成する方法は他にもありますが、これが私の最良の選択肢だと思います。私は、データを収集するために現場のオフライン TabletPC で使用される MS Access 2007 データベース (.accdb) を維持しています。オフィスに戻ったら、ユーザーはサーバーに再接続できます。pyodbc モジュールを利用して、テーブルと行をループし、オフライン フィールド データベースからサーバーの「マスター」データベースにレコードを挿入しようとしています。スクリプトの選択部分は、オフライン フィールド データベース内のレコードを取得し、後で使用するためにそれらを辞書に入れるように機能しているようです。元の投稿に基づく推奨事項には、挿入部分が辞書をループし、レコードを挿入するためのパラメーター ベースの SQL を作成するようになりました。でも、ループ内の最初のテーブルに 2 つのレコードが挿入された後、コードは次のエラーをスローします。次の 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() の後、またはテーブルを切り替える前に、「リセット/リフレッシュ」またはそれが呼び出される可能性があるものは何でも必要ですか? 最初のテーブルで終了したら、サイコロを実行します。調べてみましたが、コメント大歓迎です...

4

1 に答える 1

1

文字列を一重引用符と二重引用符の両方で囲んでいるため、ProgrammingError が発生していinsertSQLます。

フィールドが 1 つしかない理由は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)て2 番目の引数として' ,'.join('?'*len(v))渡すことで実行できます。vexecute

最終的には次のようになります。

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()
于 2013-05-08T22:38:26.590 に答える