使用pyodbc从Python应用程序向Access 2003数据库插入值

3 投票
2 回答
4710 浏览
提问于 2025-04-18 16:17

我之前在StackOverflow上查了很多问题,基本上都能找到我想要的答案,但这次我遇到的情况让我很困惑,所以我决定问问大家。

我其实不是个程序员,只是在工作中提到过Python,现在我有了一个Python项目。起初我觉得一切都还不错,但在往数据库里插入数据时,我就搞不定了。

基本问题:

我用Python和tkinter做了一个表单。当我点击表单上的一个按钮时,我希望能把一些值插入到数据库里。

具体情况:

我使用的是Python 3.4,pyodbc,还有一个Access 2003数据库。

这个数据库里只有一个表,叫做file_info,里面有以下字段,字段的数据类型在后面列出:

ID | 自动编号

filename | 文本

date | 日期/时间

batch_amount | 数字

parcel_amount | 数字

sum_amount | 数字

最终我想插入一些在其他函数中计算出来的值,但现在我只是想通过一个函数插入一些固定的值,可是一直没能成功。

连接字符串:

db_file = r'''C:\Users\amarquart\Documents\testlockboxdb.mdb'''
user = 'admin'
password = ''
odbc_conn_str = 'DRIVER={Microsoft Access Driver (*.mdb,   
*.accdb)};DBQ=%s;UID=%s;PWD=%s' % \
(db_file, user, password)

conn = pyodbc.connect(odbc_conn_str)
cur = conn.cursor()     

程序编译和运行都没问题,所以我猜测错误不是出在连接字符串上。以下是我在函数中使用的一些代码示例,但都没有成功。

def insert_data():
    sql = '''INSERT INTO file_info
    (
      [ID],
      [date],
      [filename],
      [batches_amount],
      [parcels_amount],
      [sum_amount],
    )
    VALUES
    (
      '1',
      'test',
      '8/01/2014 1:00:00 PM',
      '1',
      '1',
      '1',
    );'''

    cur.execute(sql)

    conn.commit()
    cur.commit()
    conn.close()

这段代码给出了这个错误:

在Tkinter回调中出现异常

追踪(最近的调用在最前面):

文件 "C:\Python34\lib\tkinter__init__.py",第1487行,在 call

返回 self.func(*args)

文件 "C:/Users/amarquart/PycharmProjects/Grid testing/Source/Grid testing.py",第170行,在 run 中

insert_data()

文件 "C:/Users/amarquart/PycharmProjects/Grid testing/Source/Grid testing.py",第36行,在 insert_data 中

cur.execute(sql)

pyodbc.ProgrammingError: ('42000', '[42000] [Microsoft][ODBC Microsoft Access Driver] INSERT INTO 语句中的语法错误。(-3502) (SQLExecDirectW)')

def insert_data():
    sql = ("""INSERT INTO [file_info] ([ID], [date], [filename], [batches_amount],     
         [parcels_amount], [sum_amount])
          VALUES (?, ?, ?, ?, ?, ?)""", [1, '8/01/2014 1:00:00 PM', 'test', 10, 4, 2])
    cur.execute(sql)

    conn.commit()
    cur.commit()
    conn.close()

这段代码给出的错误:

在Tkinter回调中出现异常

追踪(最近的调用在最前面):

文件 "C:\Python34\lib\tkinter__init__.py",第1487行,在 call

返回 self.func(*args)

文件 "C:/Users/amarquart/PycharmProjects/Grid testing/Source/Grid testing.py",第154行,在 run 中

insert_data()

文件 "C:/Users/amarquart/PycharmProjects/Grid testing/Source/Grid testing.py",第20行,在 insert_data 中

cur.execute(sql)

TypeError: execute 的第一个参数必须是字符串或Unicode查询。

def insert_data():
    sql = """
    INSERT INTO file_info (ID, date, filename, batches_amount, parcels_amount, sum_amount)
    VALUES (1, '8/01/2014 1:00:00 PM', 'test', 2, 2, 2)
    """ 
    cur.execute(sql)

    conn.commit()
    cur.commit()
    conn.close()    

这段代码给出的错误和上一个一样。

def insert_data():
   cur.execute("INSERT INTO file_info VALUES (AutoNumber, Text, Date/Time, Number,
               Number, Number)",
(1, 'test', '8/01/2014 1:00:00 PM', 2, 2, 2))
   conn.commit()
   cur.commit()
   conn.close()

这段代码给出的错误:

在Tkinter回调中出现异常

追踪(最近的调用在最前面):

文件 "C:\Python34\lib\tkinter__init__.py",第1487行,在 call

返回 self.func(*args)

文件 "C:/Users/amarquart/PycharmProjects/Grid testing/Source/Grid testing.py",第153行,在 run 中

insert_data()

文件 "C:/Users/amarquart/PycharmProjects/Grid testing/Source/Grid testing.py",第19行,在 insert_data 中

(1, 'test', '8/01/2014 1:00:00 PM', 2, 2, 2)

pyodbc.ProgrammingError: ('SQL中没有参数标记,但提供了6个参数', 'HY000')

我猜我尝试的所有方法都非常不正确,所以任何帮助都会非常感激。

谢谢大家。

编辑:

根据第一次回复的新尝试,唯一的不同是我使用了三重引号,因为代码跨越了两行。

cur.execute("""INSERT INTO file_info (ID, date, filename, batches_amount,   
parcels_amount, sum_amount) 
         VALUES (1, 'test', '8/01/2014 1:00:00 PM', 2, 2, 2)""")
conn.commit()

这段代码给出的错误:

在Tkinter回调中出现异常

追踪(最近的调用在最前面):

文件 "C:\Python34\lib\tkinter__init__.py",第1487行,在 call

返回 self.func(*args)

文件 "C:/Users/amarquart/PycharmProjects/Grid testing/Source/Grid testing.py",第19行,在 insert_data 中

VALUES (1, 'test', '8/01/2014 1:00:00 PM', 2, 2, 2)''')

pyodbc.ProgrammingError: ('42000', '[42000] [Microsoft][ODBC Microsoft Access Driver] INSERT INTO 语句中的语法错误。(-3502) (SQLExecDirectW)')

params = [(1, '8/01/2014 1:00:00 PM', 'test', 2, 2, 2)]
cur.executemany("""insert into file_info(ID, date, filename, batch_amount,   
parcel_amount, sum_amount)
                values (?, ?, ?, ?, ?, ?)""", params)
conn.commit()

这段代码给出的错误:

在Tkinter回调中出现异常

追踪(最近的调用在最前面):

文件 "C:\Python34\lib\tkinter__init__.py",第1487行,在 call

返回 self.func(*args)

文件 "C:/Users/amarquart/PycharmProjects/Grid testing/Source/Grid testing.py",第20行,在 insert_data 中

values (?, ?, ?, ?, ?, ?)""", params)

pyodbc.Error: ('HYC00', '[HYC00] [Microsoft][ODBC Microsoft Access Driver] 未实现的可选功能 (106) (SQLBindParameter)')

2 个回答

3

你的顺序有点问题:值应该放在列定义之后,插入的值之前,比如在你的例子中:

cur.execute("INSERT INTO file_info (ID, filename, [date], batches_amount, parcels_amount, sum_amount) 
             VALUES (1, 'test', '8/01/2014 1:00:00 PM', 2, 2, 2)")
conn.commit()

这是标准的SQL插入语法,不仅仅适用于pyodbc或Access。注意,你也可以使用占位符(?)来表示值,然后提供一个值的数组,具体可以查看文档,特别是executemany部分。

另外要注意,你只需要调用conn.commit(),而不是cur.commit(),详细信息可以参考这些其他文档中的插入部分。

编辑:根据beargle的评论,你确实需要把date放在[]里,因为它是一个保留字,这一点在你最初的尝试中是对的,但你把date和filename的值搞反了。尽量避免使用保留字作为字段名,这一点在其他数据库中也适用,不仅仅是Access。

5

你在几次尝试中已经很接近了。Date 在 Access 中是一个保留字,所以在列名周围加上方括号,并确保列的顺序和数值的顺序一致:

...
sql = """
INSERT INTO file_info (ID, [date], filename, batches_amount, parcels_amount, sum_amount)
VALUES (1, '8/01/2014 1:00:00 PM', 'test', 2, 2, 2)
""" 
cur.execute(sql)
....

根据Gord下面的评论,Access 支持带参数的查询,所以理想的代码应该是:

....
params = (1, '8/01/2014 1:00:00 PM', 'test', 2, 2, 2)
sql = """
INSERT INTO file_info (ID, [date], filename, batches_amount, parcels_amount, sum_amount)
VALUES (?, ?, ?, ?, ?, ?)
""" 
cur.execute(sql, params)
...

撰写回答