使用VBA OpenRecordset从访问查询到Excel的用户定义函数(UDF)失败-未定义函数

时间:2019-04-26 13:48:09

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

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

我收到以下错误:“ 运行时错误'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-将查询更改为make table查询。 2-将表格结果拖入Excel。尽管我也许可以(在大量的返工之后)解决这个问题,但这会导致我制作许多具有成千上万行的临时表,而且看起来并不那么光滑。

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

从长远来看,我创建了一个虚拟数据库,该数据库具有一个简单的udf公共函数,该函数返回数字1,一个简单的查询返回了三个记录以及一个函数结果字段。拖入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错误的任何查询”

3 个答案:

答案 0 :(得分:1)

  

大多数线程说无法完成,

,他们是对的。

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

答案 1 :(得分:0)

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

这是经过快速测试的Excel VBA代码段,可从包含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

答案 2 :(得分:0)

如前所述,大多数人都说这不起作用。

但是,如果您100%确信它曾经并且一次可以工作?

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

表达式服务通常不允许将VBA函数评估为安全设置以防止SQL注入,或者不允许在Access外部运行的代码允许SQL运行+调用VBA函数。一次,此功能确实默认设置为“ on”,但现在默认设置为仅访问。

您必须将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。