Skip to content

Merging Data from Queries and Recordsets to Word, Part 2

More on how to merge data from recordsets and queries to Word documents.


Access Archon #168

 


Creating Queries on-the-fly for Filtering Data

If you need to send letters to customers, and want the option of filtering by any country, not just the ones with the most customers, the frmMergeToWordDocProps form (shown in Figure D) offers another selection method:  a combo box displays all the countries from tblCustomers, and the selected country name is used to create a filtered query programmatically, which is then used to create a recordset for merging the data.

Figure D.  A form for merging data to Word using Doc Properties

After selecting a letter and a country, when you click the Merge button, a set of letters is generated, with document properties filled from a record for each letter, and the letters are left open.  Figure E shows a letter created from the Customer Letter template:

Figure E.  A letter to customers in a country selected on-the-fly

Note:  The main menu of the sample database uses components of the FileSystemObject to allow users to select the Templates folder and Documents folder.  See Chapter 9 of my new book, Access™ 2007 VBA Bible For Data-Centric Microsoft Applications, for more details on working with the FileSystemObject.


VBA Code

The cmdMerge_Click event procedure on frmMergeToWordDocProps creates a set of letters based on the selected letter template, one per customer in the filtered recordset, created on-the-fly for the selected country:

Private Sub cmdMerge_Click()

‘Creates a set of documents, one per customer

 

On Error GoTo ErrorHandler

 

   Dim appWord As Word.Application

   Dim ctl As Access.Control

   Dim dbs As DAO.Database

   Dim doc As Word.Document

   Dim docs As Word.Documents

   Dim fil As Scripting.File

   Dim fso As New Scripting.FileSystemObject

   Dim i As Integer

   Dim intSaveNameFail As Boolean

   Dim lst As Access.ListBox

   Dim prps As Object

   Dim rst As DAO.Recordset

   Dim strAddress As String

   Dim strCompanyName As String

   Dim strContactName As String

   Dim strDocsPath As String

   Dim strDocType As String

   Dim strJobTitle As String

   Dim strLongDate As String

   Dim strName As String

   Dim strPrompt As String

   Dim strQuery As String

   Dim strSaveName As String

   Dim strSaveNamePath As String

   Dim strShortDate As String

   Dim strSQL As String

   Dim strTemplate As String

   Dim strTemplateNameAndPath As String

   Dim strTemplatePath As String

   Dim strTest As String

   Dim strTestFile As String

   Dim strTitle As String

 

   ‘Check that a letter has been selected

   strTemplate = Nz(Me![cboSelectLetter].Value)

   Set ctl = Me![cboSelectLetter]

   If strTemplate = “” Then

      MsgBox “Please select a letter”

      ctl.SetFocus

      ctl.Dropdown

      GoTo ErrorHandlerExit

   Else

      strTemplate = ctl.Value

   End If

  

   ‘Check that a country has been selected

   strCountry = Nz(Me![cboSelectCountry].Value)

   Set ctl = Me![cboSelectCountry]

   If strCountry = “” Then

      strTitle = “No selection made”

      strPrompt = “Please select a country”

      MsgBox prompt:=strPrompt, _

         buttons:=vbCritical + vbOKOnly, _

         Title:=strTitle

      ctl.SetFocus

      ctl.Dropdown

      GoTo ErrorHandlerExit

   Else

      strCountry = ctl.Value

   End If

  

   ‘Set Word application variable; if Word is not running,
   ‘the error handler defaults to CreateObject

   Set appWord = GetObject(, “Word.Application”)

  

   strLongDate = Format(Date, “mmmm d, yyyy”)

   strShortDate = Format(Date, “m-d-yyyy”)

   strDocsPath = GetProperty(strName:=”DocumentsPath”, _

      strDefault:=””)

   If Right(strDocsPath, 1) <> “” Then

      strDocsPath = strDocsPath & “”

   End If

  

   strTemplatePath = GetProperty(strName:=”TemplatesPath”, _

      strDefault:=””)

   If Right(strTemplatePath, 1) <> “” Then

      strTemplatePath = strTemplatePath & “”

   End If

  

   strTemplateNameAndPath = strTemplatePath & strTemplate

  

On Error Resume Next

   ‘Check for existence of template in template folder,
   ‘and exit if not found

   Set fil = fso.GetFile(strTemplateNameAndPath)

   If fil Is Nothing Then

      strTitle = “Template not found”

      strPrompt = “Can’t find ” & strTemplate & ” in ” _

         & strTemplatePath & “; canceling”

      MsgBox strPrompt, vbCritical + vbOKOnly

      GoTo ErrorHandlerExit

   End If

  

On Error GoTo ErrorHandler

  

   ‘Create filtered query on-the-fly

   strQuery = “qryFilteredCustomers”

   strSQL = “SELECT * FROM tblCustomers ” _

      & “WHERE [Country] = ” & Chr(39) & strCountry _

      & Chr(39) & “;”

   Debug.Print “SQL Statement: ” & strSQL

   If CreateAndTestQuery(strQuery, strSQL) = 0 Then

      strTitle = “No records found”

      strPrompt = “There are no customer records for ” _

         & strCountry & “; canceling”

      MsgBox prompt:=strPrompt, _

         buttons:=vbCritical + vbOKOnly, _

         Title:=strTitle

      GoTo ErrorHandlerExit

   End If

  

   ‘Create recordset based on filtered query

   Set dbs = CurrentDb

   Set rst = dbs.OpenRecordset(strQuery)

  

   Do While Not rst.EOF

      ‘Check for required address information

      If Nz(rst![Address]) = “” Then

         GoTo ErrorHandlerExit

      End If

     

      If Nz(rst![City]) = “” Then

         GoTo ErrorHandlerExit

      End If

      

      If Nz(rst![PostalCode]) = “” Then

         GoTo ErrorHandlerExit

      End If

     

      ‘Save variables for current record

      strContactName = Nz(rst![ContactName])

      strJobTitle = Nz(rst![ContactTitle])

      If strJobTitle <> “” Then

         strName = strName & vbCrLf & strJobTitle

      End If

      strCompanyName = Nz(rst![CompanyName])

      strAddress = Nz(rst![Address]) & vbCrLf & _

         Nz(rst![City]) & ”  ” & _

         Nz(rst![Region]) & _

         ”  ” & Nz(rst![PostalCode])

      Debug.Print “Address: ” & strAddress

      If strCountry <> “USA” Then

         strAddress = strAddress & vbCrLf & strCountry

      End If

     

      ‘Create a new letter based on the selected template

      Set doc = appWord.Documents.Add(strTemplate)

     

      ‘Write information to Word custom document properties

      Set prps = doc.CustomDocumentProperties

 

On Error Resume Next

      prps.Item(“ContactName”).Value = strContactName

      prps.Item(“CompanyName”).Value = strCompanyName

      prps.Item(“Address”).Value = strAddress

      prps.Item(“Country”).Value = strCountry

      prps.Item(“TodayDate”).Value = strLongDate

     

On Error GoTo ErrorHandler

      ‘Check for existence of previously saved letter in documents folder,
      ‘and append an incremented number to save name if found

      strDocType = doc.BuiltInDocumentProperties(2)

      strSaveName = strDocType & ” to ” & strContactName

      strSaveName = strSaveName & ” on ” & strShortDate & “.doc”

      i = 2

      intSaveNameFail = True

      Do While intSaveNameFail

         strSaveNamePath = strDocsPath & strSaveName

         Debug.Print “Proposed save name and path: ” _

            & vbCrLf & strSaveNamePath

         strTestFile = Nz(Dir(strSaveNamePath))

         Debug.Print “Test file: ” & strTestFile

         If strTestFile = strSaveName Then

            Debug.Print “Save name already used: ” & strSaveName

           

            ‘Create new save name with incremented number

            intSaveNameFail = True

            strSaveName = strDocType & ” ” & CStr(i) & ” to ” & _

               strContactName

            strSaveName = strSaveName & ” on ” & strShortDate & “.doc”

            strSaveNamePath = strDocsPath & strSaveName

            Debug.Print “New save name and path: ” _

               & vbCrLf & strSaveNamePath

            i = i + 1

         Else

            Debug.Print “Save name not used: ” & strSaveName

            intSaveNameFail = False

         End If

      Loop

     

      ‘Update fields in Word document and activate it

      With appWord

         .Selection.WholeStory

         .Selection.Fields.Update

         .Selection.HomeKey Unit:=wdStory

         .ActiveDocument.SaveAs strSaveNamePath

      End With

     

      rst.MoveNext

   Loop

  

ErrorHandlerExit:

   Set appWord = Nothing

   Exit Sub

 

ErrorHandler:

   ‘Word is not running; open Word with CreateObject

   If Err.Number = 429 Then

      Set appWord = CreateObject(“Word.Application”)

      Resume Next

   Else

      MsgBox “Error No: ” & Err.Number & “; Description: “

      Resume ErrorHandlerExit

   End If

 

End Sub


References

The code in the sample database needs the following references (in addition to the default references):

Microsoft DAO 3.6 Object Library

Microsoft Scripting Runtime

Microsoft Word 11.0 Object Library

If you import code or objects into a database of your own, you may need to set one or more of these references.  The version number may differ, depending on your Office version; check the version you have.  References are set in the References dialog, opened from the VBA window.  For more information on working with references, see Access Archon #107, Working with References.


Supporting Files

The zip file containing this article, in Word 97-2003 format, plus the supporting file(s), may be downloaded from the Access Archon page of my Web site.  It is accarch168.zip, which is the last entry in the table of Access Archon columns for Access Watch.


























Document Name

Document Type

Place in

Merge Recordset to Word (AA 168).mdb

Access 2000 database (can also be used in higher versions of Access)

Wherever you want

Contact Letter DP.dot

Word 97-2003 template

Word User Templates folder, or location of your choice

Customer Letter DP.dot

Word 97-2003 template

Word User Templates folder, or location of your choice

Avery 5160 Labels.dot

Word 97-2003 template

Word User Templates folder, or location of your choice

Avery 5161 Labels.dot

Word 97-2003 template

Word User Templates folder, or location of your choice

About this author