在 VBA 中使用 DAO QueryDef 时出现“未定义函数”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7100372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 13:49:38  来源:igfitidea点击:

'Undefined function' when using DAO QueryDef in VBA

ms-accessvbaexcel-vbadaouser-defined-functions

提问by sigil

I'm assigning an Access 2007 query to a QueryDef in Excel VBA. My query calls a user-defined function, because it performs a calculation on the results of evaluating a field with a regular expression. I'm using a QueryDef because I'm collecting values in a UserForm and want to pass them to the query as parameters.

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

When I run my VBA code, I get an error: "Run-time error '3085': Undefined function 'regexFunc' in expression."

当我运行 VBA 代码时,出现错误:“运行时错误‘3085’:表达式中未定义函数‘regexFunc’。”

This questionsuggests that the problem is that DAO is unable to call Access UDFs from Excel, so I copied my UDF into the Excel VBA module, but I still get the error.

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

Access query:

访问查询:

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

Here's the Excel VBA code:

这是 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

采纳答案by sigil

I've solved this. Here's how I did it.

我已经解决了这个问题。这是我如何做到的。

First I change the query into a recordset and pass it to my filtering function:

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

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

And here's the filtering function, which creates a new array, populates it with rows that pass the UDF's boolean check, and returns it:

这是过滤函数,它创建一个新数组,用通过 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

回答by transistor1

This is how I would do it... just tested it and it works fine with my UDF:

这就是我要做的……只是测试了一下,它在我的 UDF 上运行良好:

One thing - are you required to notuse New Access.Application?

一件事 - 您是否需要使用 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

Notethat I made my underlying query a SELECT ... INTO query that creates a table called 'dataTableResults'

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

This is my query (QueryDef) in Access:

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

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

My MS-Access DB has a function called "mysqr", which gets used in the SQL above.

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

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

The table "dataTable" I'm querying against is just a list of numbers, so if my parameter "avalue" is "16", then I get the row "4" back. If I enter "4" (as in my code), I get "2" back.

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