The Usual Approach
The idea for this function came to me while responding to a question in the forums on how to check if a query exist. The usual approach is to assign the query's name to a QueryDef object and trap the error, if the query does not exist. For example:
Public Function QueryExists(QueryName As String) As Boolean
'thedbguy@gmail.com
'11/5/2021
Dim qdf As DAO.QueryDef
On Error Resume Next
Set qdf = CurrentDb.QueryDefs(QueryName)
If Err = 0 Then
QueryExists = True
Else
QueryExists = False
End If
Set qdf = Nothing
End Function
A Better Approach
Now, the above approach of using On Error Resume Next and then checking for errors is a very common approach. However, someone in the forums mentioned that this is not a very "clean" approach, because it leaves an Error Object hanging in the Errors Collection. They mentioned that their preferred method is to loop through the QueryDefs collection and check for the name of the query. For instance:
Public Function QueryExists_1(QueryName As String) As Boolean
'thedbguy@gmail.com
'11/5/2021
Dim qdf As DAO.QueryDef
Dim blnReturn As Boolean
For Each qdf In CurrentDb.QueryDefs
If qdf.Name = QueryName Then
blnReturn = True
Exit For
End If
Next
QueryExists_1 = blnReturn
End Function
An Even Better Approach
Now, that makes a lot of sense, doesn't it? However, another smart person said: "Why not just use the MSysObjects table to check if the query exist?" Well, isn't that genius. So, inspired by that comment, I decided to create the following function as another option for checking if an Access database object exist or not. It goes something like this:
Option Compare Database
Option Explicit
Public Enum dbgObjectType
dbgTable = 1
dbgQuery = 5
dbgForm = -32768
dbgReport = -32764
dbgMacro = -32766
dbgModule = -32761
dbgODBCLinkedTable = 4
dbgOtherLinkedTable = 6
End Enum
Public Function ObjectExists(ObjectName As String, ObjectType As dbgObjectType, _
Optional DatabasePath As String) As Boolean
'thedbguy@gmail.com
'11/5/2021
Dim blnReturn As Boolean
If DatabasePath = "" Then
blnReturn = DCount("*", "MSysObjects", "[Name]='" _
& ObjectName & "' AND [Type]=" & ObjectType)
ElseIf Dir(DatabasePath) = "" Then
'MsgBox "Cannot find " & DatabasePath, vbInformation, "Info!"
Debug.Print "Cannot find " & DatabasePath
blnReturn = False
Else
blnReturn = CurrentDb.OpenRecordset("SELECT Count(*) FROM [;Database=" _
& DatabasePath & "].MSysObjects WHERE [Name]='" _
& ObjectName & "' AND [Type]=" & ObjectType)(0)
End If
ObjectExists = blnReturn
End Function
As you can see, I have decided to use an enumeration and allow the user to specify which object they want to search. Also, the above function allows the user to search objects in an external database. I just thought these additional features might help make the function a lot more flexible and allow the developer to use it in multiple situations. So, now, the above approach does not rely on the Error object and also skips going through a loop to search for a single object.
Extension
Having the above function available, we can even extend the idea by creating smaller helper functions designed to search for a specific object. Here are some examples:
Public Function TableExists(TableName As String, Optional DatabasePath As String) As Boolean
TableExists = ObjectExists(TableName, dbgTable, DatabasePath)
End Function
Public Function FormExists(FormName As String, Optional DatabasePath As String) As Boolean
FormExists = ObjectExists(FormName, dbgForm, DatabasePath)
End Function
I hope the above information was useful, and I welcome any comments, recommendations, or criticisms.
As always, thanks for reading. Cheers!