使用 Pyodbc 连接到具有用户定义函数的 MS Access 文件
Posted
技术标签:
【中文标题】使用 Pyodbc 连接到具有用户定义函数的 MS Access 文件【英文标题】:Using Pyodbc to connect to an MS Access file with a User-Defined Function 【发布时间】:2021-07-02 18:43:40 【问题描述】:我正在尝试使用 pyodbc 将 python 连接到具有用户定义函数 (UDF) 的 MS Access 数据库。
数据库中有许多查询,这利用了 UDF。我想在 python 中得到这样一个查询的结果,所以我继续使用 pyodbc。 Table1_Q2 是 Access 数据库中的查询,Arc 是 Access 数据库中的 UDF。
我使用 pyodbc 从 Access DB 中的查询中获取所有值。因此,我在 Python 中使用此 SQL 查询从 Access DB 中的查询 (Table1_Q2) 中选择所有值。我收到以下错误
Execution failed on sql 'SELECT * FROM Table1_Q2': ('42000', "[42000] [Microsoft][ODBC Microsoft Access Driver] Undefined function 'Arc' in expression. (-3102) (SQLExecDirectW)")
当我从 Access DB 运行查询时,它似乎工作正常。但是当我使用 Pyodbc 连接时,它无法识别那些利用 UDF 的查询。我可以使用 Pyodbc 访问不依赖于 UDF 的其他表。
这是一个代码sn-p:
filepath = os.path.abspath('')+'\Database1.accdb'
myDataSources = pyodbc.dataSources()
# Establishing connection to Access DB
driver = myDataSources['MS Access Database']
cnxn = pyodbc.connect(driver=driver, dbq = filepath, autocommit=True)
crsr = cnxn.cursor()
table_name = 'Table1_Q2'
query = "SELECT * FROM ".format(table_name)
source_df2 = pandas.read_sql(query, cnxn)
cnxn.close()
是否需要在代码中添加一些内容以便将 UDF 也包含在 Access DB 中。
【问题讨论】:
【参考方案1】:您不能使用 pyodbc 和 Access ODBC 来运行涉及用户定义函数的查询。但是,如果您安装了完整的 Microsoft Access 应用程序,那么您的 Python 应用程序可以使用 COM 自动化来启动 Access 实例并以这种方式运行查询。
示例:对于包含名为 Table1 的表的 Access 数据库
id txt
-- -------
1 awesome
和一个包含该函数的 VBA 模块
Public Function ultra(s As String) As String
ultra = "ultra_" & s
End Function
我们可以运行类似SELECT ultra(txt) AS u_text FROM Table1 …
的查询,如下所示:
import win32com.client # needs `pip install pywin32`
# ACE.DAO constants
dbOpenDynaset = 2
db_path = r"C:\Users\Public\database1.accdb"
sql = "SELECT ultra(txt) AS u_text FROM Table1 WHERE id = 1"
obj_access = win32com.client.gencache.EnsureDispatch("Access.Application")
obj_access.OpenCurrentDatabase(db_path)
db = obj_access.CurrentDb()
try:
rs = db.OpenRecordset(sql, dbOpenDynaset)
print(rs.Fields["u_text"].Value) # ultra_awesome
except Exception as e:
print(e)
finally:
rs.Close()
obj_access.Quit()
注意事项:
-
这不适用于 Microsoft Access 运行时,仅适用于完整的 Microsoft Access 产品。
这尚未通过 Office/Access 的“点击运行”安装进行测试。
【讨论】:
要使其与运行时一起工作,请使用有效数据库启动可执行文件(或使用默认可执行文件打开有效数据库),然后附加到打开的实例。 感谢@gord-thompson 的精彩解释。至于第一行提到的win32com
,为什么需要它?您能否扩展您的注释以阐明取决于 Python 或 Office 安装版本的限制程度? (即,我的机器和 Python 是 64 位的,但我使用 Access 10 32 位)。我来自this problem,我想知道 COM 自动化是否也可以成为它的解决方案。另外,COM 与 ODBC 的速度相比如何?【参考方案2】:
MS Access 是multi-faceted software。虽然它是一个 GUI .exe 应用程序,其中包含许多组件,包括表单、报告、宏和模块,但它也是一个表的数据库(或数据存储),并通过 ODBC 或 OLEDB 以其他编程语言访问保存的查询。多年来,为了方便起见,“MS Access”被混为一谈,既指应用程序又指数据库。
当通过 ODBC 将 Python(或其他语言)连接到 Access 数据库时,您只能访问表和存储查询的底层数据库。事实上,您甚至不需要安装完整的 .exe 来连接,只需安装 ODBC 驱动程序(或 OLEDB 提供程序)即可。因此,无法访问保存在独立 VBA 模块中的用户定义函数。因此尝试在 SQL 语句或存储查询中使用它会引发错误。数据库中 UDF 的对应物是存储过程或函数,目前在 Access 数据库中不可用。
如前所述,另一种技术Component Object Model (COM) 公开了 MS Access 的 .exe 版本以使用其 object library,其中包括所有组件(表、查询、表单、报告、宏和模块)。事实上,VBA 和 Access 对象库是 Access .mdb 和 .accdb 项目中的两个默认外部引用!也许在未来的版本中,可以换掉 VBA 来用 Python 编写模块(即使那时 ODBC 仍然无法访问)!
【讨论】:
【参考方案3】:Microsoft Access 数据库引擎链接到 VB,并且可以在查询中使用 VB 单词。 VB 被设计为一种可扩展语言,当它被加载时,它会挂接到父应用程序中,从而扩展语言以包含来自父应用程序的单词。
当 Microsoft Access 是父级时,它通过加载 UDF 作为对 VB 的扩展来扩展 VB,并且 UDF 可以在查询中使用。
当 Python/ODBC 是父级时,它不会通过加载 UDF 来扩展 VB。
曾经有一个用于 VBA 的开发工具包,可让您构建父 VB 应用程序,但该工具在几年前就被撤回了:它已经有 20 年没有出售了。数据库中 UDF 的存储格式是间接记录的:它是存储在数据库中的 OLE 对象。但是如果没有 Visual Basic for Applications 扩展性 API,就无法将 UDF 链接到 Python 或 ODBC。
ODBC(“开放式数据库连接”)是一种常见的通用 SQL 标准和不包含 VBA 的驱动程序接口,因此即使在 Microsoft Access 中,包含 VBA 的查询也由 Microsoft Access 首先和最后处理,而 ODBC SQL 已修复由 Microsoft Access 启动,发送到 ODBC 驱动程序,然后在数据返回给您之前再次使用任何 UDF 调用进行修复。
【讨论】:
以上是关于使用 Pyodbc 连接到具有用户定义函数的 MS Access 文件的主要内容,如果未能解决你的问题,请参考以下文章
如果 SQL Server 是 MS 2012,则从 Pyodbc 连接到 SQL 14 Azure db
远程连接到 MS SQL - 使用 pyodbc 时出错 vs 使用 SQL Server Management Studio 成功
sqlalchemy 无法连接到 ms sql server