2

pypyodbc 如何连接到 .accdb 数据库中的链接表?这是否可能,或者这是pyodbc的限制?

我需要从 MS Acess .accdb 数据库中获取数据到 Python 中。这非常有效,我可以pypyodbc用来访问 .accdb 数据库中定义的表和查询。但是,该数据库也有链接到外部 SQL Server 的表。访问此类链接表时pypyodbc抱怨它无法连接到 SQL 服务器。

test.accdb包含两个表:(Test本地表)和cidb_ain(链接 SQL 表)

以下 Python 3 代码是我访问数据的尝试:

import pypyodbc as pyodbc

cnxn = pyodbc.connect(driver='Microsoft Access Driver (*.mdb, *.accdb)',
                      dbq='test.accdb',
                      readonly=True)

cursor = cnxn.cursor()

# access to the local table works
for row in cursor.execute("select * from Test"):
    print(row)

print('----')

# access to the linked table fails
for row in cursor.execute("select * from cidb_ain"):
    print(row)

输出:

(1, 'eins', 1)
(2, 'zwei', 2)
(3, 'drei', 3)
----
Traceback (most recent call last):
  File "test_02_accdb.py", line 14, in <module>
    for row in cursor.execute("select * from cidb_ain"):
  File "C:\software\installed\miniconda3\lib\site-packages\pypyodbc.py", line 1605, in execute
    self.execdirect(query_string)
  File "C:\software\installed\miniconda3\lib\site-packages\pypyodbc.py", line 1631, in execdirect
    check_success(self, ret)
  File "C:\software\installed\miniconda3\lib\site-packages\pypyodbc.py", line 986, in check_success
    ctrl_err(SQL_HANDLE_STMT, ODBC_obj.stmt_h, ret, ODBC_obj.ansi)
  File "C:\software\installed\miniconda3\lib\site-packages\pypyodbc.py", line 964, in ctrl_err
    raise Error(state,err_text)
pypyodbc.Error: ('HY000', "[HY000] [Microsoft][ODBC-Treiber für Microsoft Access] ODBC-Verbindung zu 'SQL Server Native Client 11.0SQLHOST' fehlgeschlagen.")

错误消息大致翻译为“与 'SQL Server Native Client 11.0SQLHOST' 的 ODBC 连接失败”。

我无法使用 pypyodbc 通过 .accdb 数据库访问 SQL Server,但cidb_ain可以从 MS Access 中查询表。此外,我可以直接连接到 SQL Server:

cnxn = pyodbc.connect(driver='SQL Server Native Client 11.0',
                      server='SQLHOST',
                      trusted_connection='yes',
                      database='stuffdb')

考虑到 (1) MS Access(和 Matlab 也是)可以使用 .accdb 文件中包含的信息来查询链接表,并且 (2) SQL Server 是可访问的,我假设问题与pypyodbc. (驱动程序名称和主机名'SQL Server Native Client 11.0SQLHOST'在错误消息中的排列方式似乎也有些可疑。)

我以前没有使用 Access 的经验,所以请耐心等待,如果我遗漏了对我来说似乎不必要的重要信息,请告诉我...

4

2 回答 2

1

首先,MS Access 是一种独特类型的数据库应用程序,它与其他 RDMS(例如 SQLite、MySQL、PostgreSQL、Oracle、DB2)有些不同,因为它附带了默认的后端 Jet/ACE SQL关系引擎(由该方式不是访问限制组件,而是通用 Microsoft 技术)和前端GUI 界面和报告生成器。本质上,Access 是对象的集合。

链接表在某种程度上是 MS Access 前端的一项功能,用于将默认的 Jet/ACE 数据库(即本地表)替换为另一个后端数据库,特别是针对您的 SQL Server。此外,链接表本身就是 ODBC/OLEDB 连接!您必须使用 DSN、驱动程序或提供程序才能在 MS Access 文件中建立和创建链接表。

因此,任何连接到 MS Access 数据库 [ driver='Microsoft Access Driver (*.mdb, *.accdb)] 的外部客户端(这里是您的 Python 脚本)实际上是连接到后端 Jet/ACE 数据库。客户端/脚本从不与前端对象交互。在您的错误中,Python 读取链接表的 ODBC 连接,并且由于 SQL Server Driver/Provider [ SQL Server Native Client 11.0SQLHOST] 从未在脚本中调用,因此脚本失败。

总之,要解决您的情况,您必须将 Python 直接连接到 SQL Server 数据库(而不是使用 MS Access 作为媒介)才能连接到那里的任何本地表,这里是cidb_ain. 只需使用 Access 链接表的连接字符串:

#(USING DSN)
db = pypyodbc.connect('DSN=dsn name;')

cur = db.cursor()
cur.execute("SELECT * FROM dbo.cidb_ain")

for row in cur.fetchall()
  print(row)

cur.close()
db.close()


# (USING DRIVER)
constr = 'Trusted_Connection=yes;DRIVER={SQL Server};SERVER=servername;' \
         'DATABASE=database name;UID=username;PWD=password'
db = pypyodbc.connect(constr)

cur = db.cursor()
cur.execute("SELECT * FROM dbo.cidb_ain")

for row in cur.fetchall()
  print(row)

cur.close()
db.close()
于 2015-09-23T19:35:55.893 回答
1

更新:

事实证明,这个问题的解决方法很简单,pyodbc.pooling = False在与Access数据库建立连接之前进行设置:

import pyodbc
# ... also works with `import pypyodbc as pyodbc`, too
pyodbc.pooling = False  # this prevents the error
cnxn = pyodbc.connect(r"DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};DBQ= ... ")


(上一个答案)

看来 pypyodbc 和 pyodbc 都不能从 Access 数据库中读取 SQL Server 链接表。但是,  System.Data.Odbc在 .NET 中可以做到这一点,所以IronPython也可以。

为了验证,我在 SQL Server 中创建了一个名为 [Foods] 的表

id  guestId  food
--  -------  ----
 1        1  pie
 2        2  soup

我在 Access 中创建了一个名为 [dbo_Foods] 的 ODBC 链接表,它指向 SQL Server 上的该表。

我还创建了一个名为 [Guests] 的本地访问表 ...

id  firstName
--  ---------
 1  Gord
 2  Jenn

...和一个名为 [qryGuestPreferences] 的已保存访问查询 ...

SELECT Guests.firstName, dbo_Foods.food
FROM Guests INNER JOIN dbo_Foods ON Guests.id = dbo_Foods.guestId;

在 IronPython 中运行以下脚本...

import clr
import System
clr.AddReference("System.Data")
from System.Data.Odbc import OdbcConnection, OdbcCommand

connectString = (
    r"DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};"
    r"DBQ=C:\Users\Public\Database1.accdb;"
)
conn = OdbcConnection(connectString)
conn.Open()

query = """\
SELECT firstName, food 
FROM qryGuestPreferences
"""
cmd = OdbcCommand(query, conn)
rdr = cmd.ExecuteReader()
while rdr.Read():
    print("{0} likes {1}.".format(rdr["firstName"], rdr["food"]))
conn.Close()

...返回

Gord likes pie.
Jenn likes soup.
于 2015-09-26T15:54:52.857 回答