Tag Archives: MS Access Tables

MS Access – Number of Attachments in an Attachment Field

I was recently answering someone’s question on how to get the count of the number of attachments in a field.

Below are 2 simple functions to get the count:

'---------------------------------------------------------------------------------------
' Procedure : GetAttachmentCount
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Get a count of the number of attachments within an attachment field
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sTable    : Table Name containing the attachment field
' sField    : Field Name of the attachment field
' sWHERE    : Criteria to filter on
'
' Usage:
' ~~~~~~
' GetAttachmentCount("tbl_Contacts", "ContactPics", "[ContactId]=127")
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2014-Feb-11                 Initial Release
'---------------------------------------------------------------------------------------
Function GetAttachmentCount(sTable As String, sField As String, sWHERE As String) As Long
    On Error GoTo Error_Handler
    'Should add validation to ensure the field is an attachment field
    Dim db              As DAO.Database
    Dim rs              As DAO.Recordset
    Dim rsAtt           As DAO.Recordset
    Dim sSQL            As String

    Set db = DBEngine(0)(0)
    sSQL = "SELECT [" & sField & "] FROM [" & sTable & "] WHERE (" & sWHERE & ");"
    Set rs = db.OpenRecordset(sSQL, dbOpenSnapshot)
    If rs.RecordCount <> 0 Then
        Set rsAtt = rs(sField).Value
        If rsAtt.RecordCount <> 0 Then
            rsAtt.MoveLast
            GetAttachmentCount = rsAtt.RecordCount
        End If
    End If

Error_Handler_Exit:
    On Error Resume Next
    Set rsAtt = Nothing
    rs.Close
    Set rs = Nothing
    Set db = Nothing
    Exit Function

Error_Handler:
    MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: GetAttachmentCount" & vbCrLf & _
           "Error Description: " & Err.Description, _
           vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function
'---------------------------------------------------------------------------------------
' Procedure : GetAttachmentCount2
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Get a count of the number of attachments within an attachment field
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sTable    : Table Name containing the attachment field
' sField    : Field Name of the attachment field
' sWHERE    : Criteria to filter on
'
' Usage:
' ~~~~~~
' GetAttachmentCount2("tbl_Contacts", "ContactPics", "[ContactId]=127")
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2014-Feb-11                 Initial Release
'---------------------------------------------------------------------------------------
Function GetAttachmentCount2(sTable As String, sField As String, sWHERE As String) As Long
    On Error GoTo Error_Handler
    'Should add validation to ensure the field is an attachment field
    Dim db              As DAO.Database
    Dim rs              As DAO.Recordset
    Dim sSQL            As String

    Set db = DBEngine(0)(0)
    sSQL = "SELECT Count([" & sField & "].FileName) AS FileNameCount" & vbCrLf & _
           " FROM [" & sTable & "]" & vbCrLf & _
           " WHERE (" & sWHERE & ");"
    Set rs = db.OpenRecordset(sSQL, dbOpenSnapshot)
    If rs.RecordCount <> 0 Then
        rs.MoveLast
        GetAttachmentCount2 = rs![FileNameCount]
    End If

Error_Handler_Exit:
    On Error Resume Next
    rs.Close
    Set rs = Nothing
    Set db = Nothing
    Exit Function

Error_Handler:
    MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: GetAttachmentCount2" & vbCrLf & _
           "Error Description: " & Err.Description, _
           vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

As you can see based on the GetAttachmentCount2 procedure, you can extract a count using a simple Count() function in a query. So actually no need for VBA in this case. So you can easily add a count to a query based on the AttachmentFieldName.FileName

NumberOfAttachments: Count(AttachmentFieldName.FileName)

MS Access – VBA – Reset the Table Lookup Display Control Property to Text Box

I recently took over a database in which the previous dba had set a number of table fields to act as lookup displaying combo boxes. This is a horrible thing to do, IMHO, and since users should never directly have access to tables, and should be working through forms, there is absolutely no reason for this in the first place. Now not wanting to have to go through hundreds of tables and countless fields resetting this property manually, I decided to write a simple function to perform this cleanup for me. Hopefully this might help someone else out with this issue.

'---------------------------------------------------------------------------------------
' Procedure : RemoveAllTableLookupCboLst
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Loops through all the tables in a database and removes/resets the Lookup
'             Display Control property to reset it to a simple textbox rather than a
'             combo box or listbox.  Never needed as users should never access tables
'             directly!
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
'             (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: None required
'
' Usage:
' ~~~~~~
' Call RemoveAllTableLookupCboLst
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2013-05-17              Initial Release
' 2         2019-02-23              Updated Header
'                                   Updated Error Handler
'---------------------------------------------------------------------------------------
Function RemoveAllTableLookupCboLst() As String
    Dim db              As DAO.Database
    Dim td              As DAO.TableDefs
    Dim t               As DAO.TableDef
    Dim fld             As Field
 
    On Error GoTo Error_Handler

    Set db = CurrentDb()
    Set td = db.TableDefs
    On Error Resume Next
    For Each t In td    'Loop through each table
        If Left(t.Name, 4) <> "MSys" Then    'Don't mess with system tables!
            For Each fld In t.Fields    'loop through each field
                If fld.Type = dbText Then    'Only modify Text fields
                    fld.Properties("DisplayControl") = acTextBox
                End If
            Next fld
        End If
    Next t

Error_Handler_Exit:
    On Error Resume Next
    If Not td Is Nothing Then Set td = Nothing
    If Not db Is Nothing Then Set db = Nothing
    Exit Function

Error_Handler:
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: RemoveAllTableLookupCboLst" & vbCrLf & _
           "Error Description: " & Err.Description & _
           Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
           , vbOKOnly + vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

MS Access – VBA – Exports All Tables to Another Database

I recently needed to export all the tables from a secured mdb into a new accdb I was creating. Now, you can export each table, 1 by 1, manually, but the becomes tiresome and tedious quite quickly. Instead, I wrote the following simple function to do the work for me.

All it does is loop through the table definitions to identify each table in the database, and as it does, I export that table.

Continue reading

MS Access – Persistent Connection in a Split Database

 

The Art of Database Development: Establishing a Persistent Connection

When it comes to database development, seasoned professionals understand that best practices dictate a clear separation between two essential components: the Back-End, where your data resides, and the Front-End, which encompasses all the interactive elements like queries, forms, reports, macros, and modules. However, one crucial aspect that many developers overlook is the significance of maintaining a persistent connection between the Front-End and Back-End.
 
Continue reading

MS Access – VBA – Export Database Objects to Another Database

I while back, I wanted to unsecure a database.  Instead of messing around with accounts….  I simply decided to export everything, all the database objects: tables, queries, forms, reports, macros, modules into a new unsecured database.  Now you can right-click on each object, one at a time, select export, browse to find the database, click ok, ok…   but this is simply a complete waste of time.

Don’t ask me why you can’t, using multiple selected objects, perform an export?!  this to me is the type of oversight made by MS’ development team, but this is another discussion altogether.

The good news is that we can easily accomplish a complete export using the power of VBA and a few very simple lines of code!

'---------------------------------------------------------------------------------------
' Procedure : ExpObj2ExtDb
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Export all the database object to another database
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sExtDb    : Fully qualified path and filename of the database to export the objects
'             to.
'
' Usage:
' ~~~~~~
' ExpObj2ExtDb "c:\databases\dbtest.accdb"
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2008-Sep-27                 Initial Release
'---------------------------------------------------------------------------------------
Public Sub ExpObj2ExtDb(sExtDb As String)
    On Error GoTo Error_Handler
    Dim qdf             As QueryDef
    Dim tdf             As TableDef
    Dim obj             As AccessObject

    ' Forms.
    For Each obj In CurrentProject.AllForms
        DoCmd.TransferDatabase acExport, "Microsoft Access", sExtDb, _
                               acForm, obj.Name, obj.Name, False
    Next obj

    ' Macros.
    For Each obj In CurrentProject.AllMacros
        DoCmd.TransferDatabase acExport, "Microsoft Access", sExtDb, _
                               acMacro, obj.Name, obj.Name, False
    Next obj

    ' Modules.
    For Each obj In CurrentProject.AllModules
        DoCmd.TransferDatabase acExport, "Microsoft Access", sExtDb, _
                               acModule, obj.Name, obj.Name, False
    Next obj

    ' Queries.
    For Each qdf In CurrentDb.QueryDefs
        If Left(qdf.Name, 1) <> "~" Then    'Ignore/Skip system generated queries
            DoCmd.TransferDatabase acExport, "Microsoft Access", sExtDb, _
                                   acQuery, qdf.Name, qdf.Name, False
        End If
    Next qdf

    ' Reports.
    For Each obj In CurrentProject.AllReports
        DoCmd.TransferDatabase acExport, "Microsoft Access", sExtDb, _
                               acReport, obj.Name, obj.Name, False
    Next obj

    ' Tables.
    For Each tdf In CurrentDb.TableDefs
        If Left(tdf.Name, 4) <> "MSys" Then    'Ignore/Skip system tables
            DoCmd.TransferDatabase acExport, "Microsoft Access", sExtDb, _
                                   acTable, tdf.Name, tdf.Name, False
        End If
    Next tdf

Error_Handler_Exit:
    On Error Resume Next
    Set qdf = Nothing
    Set tdf = Nothing
    Set obj = Nothing
    Exit Sub

Error_Handler:
    MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: ExpObj2ExtDb" & vbCrLf & _
           "Error Description: " & Err.Description, _
           vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Sub

Voilà, nothing to it (once you do it once).

MS Access – VBA – Delete Captions from Table Fields

I used to use table field captions extensively until I started to run into a weird problem in which I couldn’t reassign a fieldname in a query with a new name.  No matter what I did, it always reverted to the field caption.  After a lot of testing, I eventually found the link.  Delete the link and the SQL Alias worked, put the caption back and again the Alias wouldn’t work?!

It has now become common practice for me, as well as many other professional developers, to delete all the field captions from any database I work on to ensure the flexibility of ALIASes in my queries.  As such, I developed the procedure below to quickly delete the captions from all the tables within a database, instead of trying to do this manually.

'---------------------------------------------------------------------------------------
' Procedure : ClearAllCaptions
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Remove all captions from all the fields in all the non-system tables
'             because of issues that caption cause, mainly:
'               Captions prevent you from being able to assign a new name in a query
'               unless you do a calculation with it
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Usage:
' ~~~~~~
' Call ClearAllCaptions
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2012-Jun-19                 Initial Release
'---------------------------------------------------------------------------------------
Public Sub ClearAllCaptions()
    On Error GoTo Error_Handler
    Dim Db              As DAO.Database
    Dim sPropName       As String
    Dim fld             As Field
    Dim iTbls           As Integer
    Dim iNonSysTbls     As Integer
    Dim ifldCount       As Integer

    Set Db = CurrentDb
    sPropName = "Caption"
    iNonSysTbls = 0
    ifldCount = 0

    For iTbls = 0 To Db.TableDefs.Count - 1             'Loop through the table collection
        If (Db.TableDefs(iTbls).Attributes And dbSystemObject) = 0 Then    'Ensure the table isn't a system table
            'we don't want to mess around with them
            For Each fld In Db.TableDefs(iTbls).Fields  'Loop through the table fields
                fld.Properties.Delete (sPropName)   'Delete any captions
                ifldCount = ifldCount + 1
            Next fld
            iNonSysTbls = iNonSysTbls + 1
        End If
    Next iTbls

    If iTbls > 0 Then
        MsgBox "Out of a total of " & iTbls & " tables in the current database, " & _
               iNonSysTbls & " non-system tables " & _
               " were processed, in which a total of " & ifldCount & " fields " & _
               "had their '" & sPropName & "' property deleted."
    End If

Error_Handler_Exit:
    On Error Resume Next
    Set Db = Nothing
    Exit Sub

Error_Handler:
    If Err.Number = 3265 Then
        Resume Next
    Else
        MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
               "Error Number: " & Err.Number & vbCrLf & _
               "Error Source: ClearAllCaptions" & vbCrLf & _
               "Error Description: " & Err.Description, _
               vbCritical, "An Error has Occurred!"
        Resume Error_Handler_Exit
    End If
End Sub

MS Access – AutoNumber Field

We tend to see numerous questions relating to MS Access Autonumbers. Specifically, regarding autonumber not following sequence, skipping sequence.

What Are AutoNumbers and What Aren’t They!

Regardless of how one might interpret what is written in the help files, AutoNumbers should never, ever, ever, be relied upon as a sequential number. Nor should they ever be used/displayed to the end-user. The simple fact of the matter is that AutoNumbers are merely unique identifiers for each record. Even when set to be incremental, the AutoNumber can be indexed even though no record was actually inserted into the table. This is not a bug, this is simply the way Access was developed.

Sequential Numbering

So what does one do if they require a sequential number to attribute to each record.

The solution is actually very simple. Create a new numeric field in your table and then you can used an equation such as =Nz(Dmax(…), 0) + 1 to generate the next number in your sequence. At the end of the day, if you want a sequential number that will not jump sequence and can be faithfully relied upon, you have to create it yourself!

MS Access – VBA – Retrieve a Random Record

Another interesting question I was once asked on an Access forum was how can one retrieve a random record in a form?

I was actually perplexed as to how to approach this request, but it really isn’t that complicated at the end of the day. The code below demonstrates one possible method.

'---------------------------------------------------------------------------------------
' Procedure : GetRndRec
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Goto/retrieve a random record
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2008-Dec-21             Initial Release
'---------------------------------------------------------------------------------------
Function GetRndRec()
On Error GoTo Error_Handler
    Dim db          As DAO.Database
    Dim rs          As DAO.Recordset
    Dim tblName     As String   'Table to pull random record from
    Dim iRecCount   As Long     'Number of record in the table
    Dim iRndRecNum  As Integer
    
    tblName = "YourTableName"
    Set db = CurrentDb()
    Set rs = db.OpenRecordset(tblName, dbOpenSnapshot, dbReadOnly, dbReadOnly)
    
    If rs.RecordCount <> 0 Then 'ensure there are records in the table before proceeding
        With rs
            rs.MoveLast   'move to the end to ensure accurate recordcount value
            iRecCount = rs.RecordCount
            iRndRecNum = Int((iRecCount - 1 + 1) * Rnd + 1) 'Get Random Rec Number to use
            rs.MoveFirst
            .Move CLng(iRndRecNum)
            GetRndRec = ![YourFieldName]
        End With
    End If

Resume Error_Handler_Exit
    On Error Resume Next
    'Cleanup
    rs.Close
    Set rs = Nothing
    Set db = Nothing
    Exit Function

Error_Handler:
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: GetRndRec" & vbCrLf & _
           "Error Description: " & Err.Description _
           , vbOKOnly + vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

MS Access – VBA – Determine in Which Table a Field is Located

This was the question put forth by someone on an Access Forum recently and I thought I’d share one possible way to determine this.

This is a brute force method, but it works! I simply loop through all the tables one by one and loop through all the fields within each table one by one. It is that simple. Here is the code.

'---------------------------------------------------------------------------------------
' Procedure : WhereFieldLocated
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Determine/Locate in which Table(s) a field is located
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFieldName: The name of the field you are trying to locate
'
' Usage:
' ~~~~~~
' WhereFieldLocated "Filed1"
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2011-Aug-17                 Initial Release
'---------------------------------------------------------------------------------------
Function WhereFieldLocated(sFieldName As String)
    Dim db            As DAO.Database
    Dim td            As DAO.TableDefs
    Dim fld           As DAO.Field

    Set db = CurrentDb()
    Set td = db.TableDefs
    For Each t In td    'loop through all the tables in the database
        If Left(t.Name, 4) = "MSys" Then GoTo Continue
        For Each fld In t.Fields    'loop through all the fields of the table
            If fld.Name = sFieldName Then
                Debug.Print t.Name
            End If
        Next
Continue:
    Next

    Set fld = Nothing
    Set td = Nothing
    Set db = Nothing
End Function

MS Access – Tables – Where to Create Relationships? In the Front-End or Back-End?

Now here is a question I had myself many years ago and could never find a proper answer to! And yet it is such a basic element and such an important one at that!!!

So when one creates a split database (which they all should be), where do you create the tables relationships exactly? Do you create the MS Access table relationship within the Front-End or the Back-End?

The short answer is, in the Back-End. Here are a few explanation from a couple fellow MVPs taken from a recent forum question.

Continue reading