使用 Pyodbc 连接到具有用户定义函数的 MS Access 文件

问题描述

我正在尝试使用 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 的其他表。

这是一个代码片段:

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 中。

解决方法

您不能使用 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()

注意事项:

  1. 这不适用于 Microsoft Access Runtime,仅适用于完整的 Microsoft Access 产品。
  2. 这尚未通过 Office/Access 的“点击运行”安装进行测试。
,

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 访问)!

,

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 ('Open DataBase Connectivity') 是不包含 VBA 的通用通用 SQL 标准和驱动程序接口,因此即使在 Microsoft Access 中,包含 VBA 的查询也由 Microsoft Access 首先和最后处理,ODBC SQL 已修复由 Microsoft Access 启动,发送到 ODBC 驱动程序,然后在数据返回给您之前再次使用任何 UDF 调用进行修复。