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

时间:2011-08-17 22:37:35

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

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

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

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

2 个答案:

答案 0 :(得分: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”。

答案 1 :(得分:1)

我已经解决了这个问题。我就是这样做的。

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

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