【问题标题】:User Defined Functions (UDF) from Access Query to Excel using VBA OpenRecordset failed - Undefined Function使用 VBA OpenRecordset 从 Access Query 到 Excel 的用户定义函数 (UDF) 失败 - 未定义函数
【发布时间】:2019-09-16 01:15:17
【问题描述】:

如果 Excel 有 UDF,我如何从 Access 中获取查询结果?

我收到以下错误:“运行时错误'3085':表达式中未定义函数'XXXX'”。从 Excel VBA 打开(访问查询)记录集时发生错误。正在打开的查询具有触发错误的用户定义函数 (UDF)。

代码在 Excel Office 365 中。查询在 Access Office 365 中。

我已经成功地使用了被调用的查询(以及其他使用 UDF 的查询)大约十二个月,并且“突然”它不再工作了。我用谷歌搜索并测试了许多选项,但都没有成功。

大多数线程说它无法完成,或者不使用 udf 而是尝试使用有效的内置函数。我正在挑战这些回应,因为它以前曾奏效过。我使用的主要 udf 是一个名为“iMax”的 udf,它在其他帖子中有所介绍。它的功能类似于 Excel 中的 max()。 (No max(x,y) function in Access)

我还看到了建议分两步执行此操作的线程: 1 - 将查询更改为生成表查询。 2 - 将表格结果拉入 Excel。虽然我可能会侥幸逃脱(经过多次返工),但它会导致我制作许多包含成千上万行的临时表,而且看起来不太流畅。

我已经编译了 vba 并压缩了数据库,对我的问题没有影响。

作为一个长镜头,我创建了一个虚拟数据库,其中包含一个返回数字 1 的简单 udf 公共函数、一个返回三个记录的简单查询和一个用于函数结果的字段。拉入 Excel 时也会出现同样的错误。

Sub RunQuery()
Dim MyDatabase As dao.Database
Dim qdf As dao.QueryDef
Dim rs As dao.Recordset
Dim qryname As object
Dim SheetName As String

Set MyDatabase = DBEngine.OpenDatabase _
("SomePath\SomeFilename.accdb")

For Each qryname In Range("SomeRange")
    Set rs = MyDatabase.OpenRecordset(qryname)      '<<<ERROR IS HERE
    SheetName = "SomeSheetName"
        With Sheets(SheetName)
            .ListObjects(SomeTableName).DataBodyRange.Rows.ClearContents
            .Range("A2").CopyFromRecordset rs
        End With
    Set rs = Nothing
    Set qdf = Nothing
Next qryname

End Sub

对于 For 循环中没有 udf 的所有查询,会将结果提取并转储到 Excel 中的一系列表中。任何在“Set rs = Mydatabase.OpenRecordset(qryname)

处出现 udf 错误的查询

【问题讨论】:

    标签: excel ms-access vba user-defined-functions


    【解决方案1】:

    大部分帖子都说做不到,

    他们是对的。

    您唯一的选择是使用自动化打开 Access 实例,并在其中运行查询。

    【讨论】:

    • Gustav - 这已经为我和办公室的其他人在同一个查询上工作了好几个月。为什么它以前可以工作而现在突然不行了?也许作为后续行动,您对自动化有什么建议吗?我将不得不谷歌,但任何帮助将不胜感激。
    • 不知道为什么它有效,它不应该。 @HansUp 提供了这个例子。
    【解决方案2】:

    如果您按照 Gustav 的建议在 Access 应用程序会话中运行查询,则表达式服务可以处理您查询中的 UDF。

    这是一个快速测试的 Excel VBA sn-p,它从包含 UDF 的查询中提取数据:

    Const cstrDbFile As String = "C:\share\Access\Database2.accdb"
    Dim objAccess As Object
    Dim rs As Object
    Dim ws As Worksheet
    Dim strSelect As String
    
    Set objAccess = CreateObject("Access.Application")
    objAccess.Visible = True ' useful during testing '
    objAccess.OpenCurrentDatabase "C:\share\Access\Database2.accdb"
    strSelect = "SELECT ID, DummyFunction('a', '', 'c') FROM Dual;"
    Set rs = objAccess.CurrentDb.OpenRecordset(strSelect)
    If Not rs.EOF Then
        Set ws = ThisWorkbook.Sheets("Sheet1")
        ws.Range("A1").CopyFromRecordset rs
    End If
    rs.Close
    objAccess.Quit
    

    【讨论】:

    • 谢谢 HansUp。这解决了我的问题。它运行时不会出现运行时错误。
    【解决方案3】:

    好吧,如前所述,大多数人都说这不应该工作。

    但是,如果您 100% 确定它曾经并且确实在某个时间工作过?

    您需要设置 JET(现为 ACE)数据库引擎的“沙盒”模式。

    表达式服务通常不允许将 VBA 函数的评估作为安全设置来防止 SQL 注入,也不允许在 Access 外部运行代码以允许 SQL 运行 + 调用 VBA 函数。曾经,此功能默认为“开启”,但现在默认设置为仅访问。

    您必须将 Access 应用程序所在的文件夹设置为受信任。这应该允许 VBA 函数现在可以工作。因此,请确保将文件夹设置为受信任。

    如果您的访问应用程序所在的位置(文件夹)不受信任,则 Access 将使用沙盒模式,并且 SQL 中的 VBA 将不会运行。

    如果该位置是受信任的,那么访问将使用您计算机上的注册表设置。

    我敢打赌,该位置不受信任 - 因此您始终会在 Access 中获得 SQL 沙盒模式。

    如果您 100% 确定文件夹位置在 Access 中设置为受信任,但仍然收到错误消息,则必须更改 Access“沙盒”模式的注册表设置。

    此处概述了注册表中的设置: https://support.office.com/en-us/article/Turn-sandbox-mode-on-or-off-to-disable-macros-8CC7BAD8-38C2-4A7A-A604-43E9A7BBC4FB

    注册表设置为:

    对于 x32 位访问:

    Software\Microsoft\Office\ClickToRun\Registry\Machine\Software\
    Wow6432Node\Microsoft\Office\16.0\Access Connectivity Engine\Engines
    

    以上适用于 Office 2016

    14 = 2010

    15 = 2013

    16 = 2016

    沙盒模式的关键值为: 0到3

    0 沙盒模式始终处于禁用状态。

    1 沙盒模式用于 Access,但不适用于非 Access 程序。

    2 沙盒模式用于非 Access 程序,但不适用于 Access。

    3 始终使用沙盒模式。这是默认值,在安装 Access 时设置

    因此,从上面看,您需要设置为 0。

    【讨论】:

      猜你喜欢
      • 2015-08-12
      • 2020-12-04
      • 2012-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多