当sql查询调用vba函数,而该函数引发错误时,错误处理代码无法处理该错误。
请参阅下面的示例。在执行Set rst = db.OpenRecordset(strSql)
时,strSql中对GetId()的调用会生成错误。On Error GoTo Err_Test
错误处理程序不处理此错误!
Public Function GetId() As Long
Err.Raise 11 'Divide by zero error
End Function
Public Function Test() As String
On Error GoTo Err_Test
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim strSql As String
Set db = CurrentDb()
strSql = "Select * FROM MyTable WHERE MyTable.Id = GetId()"
Set rst = db.OpenRecordset(strSql)
Test = rst!name
Exit_Test:
If Not rst Is Nothing Then
rst.Close
Set rst = Nothing
End If
Set db = Nothing
Exit Function
Err_Test:
MsgBox Error$
Resume Exit_Test
End Function
为什么错误会从错误处理程序中转义?当sql调用生成异常的vba函数时,是否有一些方法可以优雅地处理它?
我知道,如下所示,从sql字符串中删除函数调用将使错误处理程序能够捕获错误。
Dim id as Long
id = GetId()
strSql = "Select * FROM MyTable WHERE MyTable.Id = " & id
这是唯一的路吗?如果是这样,是否应该避免在sql查询字符串中使用函数调用来避免未处理的异常?
我对观察到的行为的看法是:
运行"Select * FROM MyTable WHERE MyTable.Id = GetId()"
时,GetId()
由查询引擎计算,而不是由Test()
计算,因此Test()
中的错误处理程序无法捕获运行时错误。这与将SQL放入查询并运行该查询是一样的。
执行"Select * FROM MyTable WHERE MyTable.Id = " & GetId()
时,GetId()
将由Test()
求值
这将是运行示例(在VBA函数中打开记录集)的"正常"方式
但是,您也可以在查询中使用类似GetId()
的VBA函数。您只需要确保该函数足够简单,它不会触发运行时错误,或者该函数有自己的错误处理程序。
如果函数只运行一次(在WHERE子句中),则可以接受MsgBox作为错误处理程序。如果该函数对每一行都运行(即它在SELECT子句中),这可能会导致真正糟糕的用户体验p
因此,请确保在这种情况下,函数返回错误代码或NULL或任何适用的值,如vacip所写。