【问题标题】:'Undefined function' when using DAO QueryDef in VBA在 VBA 中使用 DAO QueryDef 时出现“未定义函数”
【发布时间】:2011-10-29 08:18:25
【问题描述】:

我正在将 Access 2007 查询分配给 Excel VBA 中的 QueryDef。我的查询调用用户定义函数,因为它对使用正则表达式评估字段的结果执行计算。我使用 QueryDef 是因为我在 UserForm 中收集值并希望将它们作为参数传递给查询。

当我运行我的 VBA 代码时,我收到一个错误:“运行时错误 '3085': Undefined function 'regexFunc' in expression。”

This question 提示问题是 DAO 无法从 Excel 调用 Access UDF,因此我将我的 UDF 复制到 Excel VBA 模块中,但仍然出现错误。

访问查询:

select field1 from dataTable where regexFunc(field1)=[regexVal]

这是 Excel VBA 代码:

'QueryDef function
Sub makeQueryDef (str As String)

Dim qdf As QueryDef
Dim db As Database

Set db = OpenDatabase(DBpath)
Set qdf = db.QueryDefs("paramQuery")
qdf.Parameters("regexVal") = (str="test")
doSomething qdf

End Sub

'Regex function copied from Access VBA module to Excel VBA module
Function regexFunc(str As String) As Boolean

Dim re As RegExp
Dim matches As MatchCollection

regexFunc = False
Set re = New RegExp
re.Pattern = "\reg[ex](pattern)?"
Set matches = re.Execute(str)
If matches.Count <> 0 Then
    regexFunc = True
End If

End Function

【问题讨论】:

  • 你不能这样做:你的函数在 Excel 中,但是你的 SQL 正在通过 DAO 对你的 Access db 执行,它对 VBA/你的函数一无所知。这就是 Dick K. 在您提到的问题中所说的。
  • 此知识库链接描述了您的问题:support.microsoft.com/kb/180810
  • @TimWilliams,好的。如果我使用没有 UDF 的查询,我想我可以将一列附加到它的记录集(我从 qdf.openrecordset 获得)并使用使用 Excel VBA 版本的 UDF 计算的值填充该列。这是最好的方法,还是有更简单的方法来获得我想要的东西?编辑:感谢您的链接。
  • 看起来你正在使用 UDF 来过滤返回的记录,所以如果你要在查询之后使用它,你需要先返回所有记录,或者想出一个普通的SQL“第一次通过”过滤器至少限制了查询的结果。这样做有多重要取决于您的表中有多少条记录:如果一个可管理的数字那么是的,您可以只执行正则表达式后查询。
  • 但是 Left()、Mid() 和所有这些字符串处理函数都可以从 Access 外部使用,而 UDF 则不能。所以,这对我来说似乎是最强大的解决方案。

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


【解决方案1】:

这就是我的做法……刚刚测试过它,它适用于我的 UDF:

一件事 - 您是否需要使用 New Access.Application?

Sub GetMyDataWithUDF()
    Dim oApp As Access.Application
    Dim qd As QueryDef

    sFileName = "C:\Users\AUser\Desktop\adatabase.mdb"
    Set oApp = New Access.Application
    oApp.OpenCurrentDatabase (sFileName)

    Set qd = oApp.CurrentDb.QueryDefs("Query1")

    If oApp.DCount("*", "MSysObjects", "Name='dataTableResults'") > 0 Then _
        oApp.CurrentDb.TableDefs.Delete "dataTableResults"

    qd.Parameters("avalue") = "4"
    qd.Execute

    oApp.Quit
    Set oApp = Nothing

    Dim oRS As ADODB.Recordset
    sConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & sFileName & ";User Id=admin;Password=;"
    Set oRS = New ADODB.Recordset
    oRS.Open "SELECT * FROM dataTableResults", sConn
    Sheet1.Cells.Clear
    Sheet1.Range("A1").CopyFromRecordset oRS
    oRS.Close
    Set oRS = Nothing
End Sub

注意,我将基础查询设为 SELECT ... INTO 查询,该查询创建了一个名为“dataTableResults”的表

这是我在 Access 中的查询 (QueryDef):

SELECT dataTable.Field1, dataTable.Field2 INTO dataTableResults
FROM dataTable
WHERE mysqr(dataTable.Field1)=[avalue];

我的 MS-Access DB 有一个名为“mysqr”的函数,它在上面的 SQL 中使用。

Function mysqr(Num)
        mysqr = Num * Num
    End Function

我要查询的表“dataTable”只是一个数字列表,所以如果我的参数“avalue”是“16”,那么我会返回“4”行。如果我输入“4”(在我的代码中),我会得到“2”。

【讨论】:

  • 另外——你的示例代码对我来说不是 100% 清楚。您是尝试打开 Access 数据库并在数据库中创建 QueryDef,还是尝试连接到数据库并查询数据?如果您需要打开数据库,请参考 MS-Access 并执行以下操作:Dim oApp as Access.Application : Set oApp = New Access.Application : oApp.OpenCurrentDatabase(FilePath) : Set qd = oApp.CurrentDb.CreateQueryDef( ... ) : ... etc ... 这不是我的想法,所以如果您需要更多细节,请告诉我。
  • 我包含了 VBS 正则表达式 5.5 参考。我将正则表达式 UDF 代码复制到与 QueryDef 代码相同的 Excel VBA 模块中。不,我不需要用access.application 调用Access,我可以用dim db as database set db=opendatabase("mypath") 做到这一点,我已经测试过了。问题在于 Excel 调用 UDF。
  • 澄清代码:我正在尝试获取存储的 Access 查询的结果并将它们输出到 Excel 电子表格。
  • 您可以在 Excel 中使用 DAO,如果您正在查询 Access,有些人建议这样做。
  • 对不起 - 我现在知道了。您在 Access 中有一个包含用户定义函数的查询,并且您需要 Excel 中的结果。
【解决方案2】:

我已经解决了这个问题。以下是我的做法。

首先我将查询更改为记录集并将其传递给我的过滤函数:

function filteredQDF(qdf As QueryDef, boolVal As Boolean) As Variant

Dim rs As Recordset
Dim rows_rs As Variant
Dim rs_new As Recordset
Dim filtered As Variant


Set rs = qdf.OpenRecordset

rs.MoveLast
rs.MoveFirst

rows_rs = rs.GetRows(rs.RecordCount)
rows_rs = Application.WorksheetFunction.Transpose(rows_rs)
filtered = filterFunction(rows_rs, boolVal)

filteredQDF = filtered

End Function

这里是过滤函数,它创建一个新数组,用通过 UDF 布尔检查的行填充它,然后返回它:

Function filterFunction(sourceArray As Variant, checkValue As Boolean) As Variant


Dim targetArray As Variant
Dim cols As Long
Dim targetRows As Long
Dim targetCursor As Long


'get # of columns from source array
cols = UBound(sourceArray, 2)

'count total number of target rows because 2D arrays cannot Redim Preserve
'checking sourceArray(r,2) because that's the criterion column
targetRows = 0
For r = 1 To UBound(sourceArray, 1)
    If myUDF(CStr(sourceArray(r, 2))) = checkValue Then
        targetRows = targetRows + 1
    End If
Next

'set minimum target rows to 1 so that function will always return an array
If targetRows = 0 Then
    targetRows = 1
End If

'redim target array with target row count
ReDim targetArray(targetRows, cols)

'set cursor for assigning values to target array
targetCursor = 0


'iterate through sourceArray, collecting UDF-verified rows and updating target cursor to populate target array
For r = 1 To UBound(sourceArray, 1)
    If myUDF(CStr(sourceArray(r, 2))) = checkValue Then
        For c = 1 To cols
            targetArray(targetCursor, c - 1) = sourceArray(r, c)
        Next
        targetCursor = targetCursor + 1
    End If
Next


'assign return value
filterFunction = targetArray

End Function

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 1970-01-01
    • 2020-02-21
    相关资源
    最近更新 更多