|
Create a new Word document using automation from Access using VBA. Write an optional description and then make a table with the results of an Access query. Add borders and shading to the table. Optionally specify Landscape orientation instead of Portrait (default). Create a page header with the query name, page number, and page count.
Download zipped BAS file with module that you can import mod_aWordDocumentFromQuery_s4p__BAS.zip
Download sample Access database with test data aWordDocument_AccessQuery_s4p__ACCDB.zip
If you have trouble with the downloads, you may need to unblock the ZIP file, aka remove Mark of the Web, before extracting the file. Here are steps to do that: https://msaccessgurus.com/MOTW_Unblock.htm
Option Compare Database 'Ignore Case Option Explicit 'variables must be declared '261010 '*************** Code Start *************************************************** ' module: mod_aWordDocumentFromQuery_s4p ' Purpose : Automate Word: Create a new Word document from data in Access Query ' Specify query name: results to Word table with borders + shading ' Page header with page number and more ' show information on StatusBar as code runs ' (File, Options, Current Database, check: Display Status Bar) ' Optionally: ' Description to be written to document before table ' Orientation is Portrait unless Landscape specified ' Margins can be Narrow ' Author : crystal (strive4peace) ' this code: https://msaccessgurus.com/VBA/aWord_NewFromQuery.htm ' LICENSE : ' You may freely use and share this code, but not sell it. ' Keep attribution. Mark your changes. Use at your own risk. '------------------------ ' PROCEDURES ' aWordDocumentFromQuery '------------------------ test procedures ' test_aWordDocumentFromQuery_SpecialChar ' test_aWordDocumentFromQuery_Element ' test_aWordDocumentFromQuery_BogusError ' test_aWordDocumentFromQuery_NoRecordsError ' test_aWordDocumentFromQuery_CantOpenError '------------------------------------------------------------------------------- ' '------------------------------------------------------------------------------- ' aWordDocumentFromQuery '------------------------------------------------------------------------------- Public Sub aWordDocumentFromQuery( _ psQueryName As String _ ,Optional psDescription As String = "" _ ,Optional piOrientation As Integer = 0 _ ,Optional pbNarrow As Boolean = False _ ) '260930,1004,5,6,7,8 'PARAMETERs ' psQueryName = name of query to show in a Word table 'Optional ' psDescription - Text to write above the table ' piOrientation - Default = 0 = Portrait. ' Landscape = 1 ' pbNarrow - Default = False. ' True = set to narrow margins (0.5 inch) 'object variables Dim db As DAO.Database Dim rs As DAO.Recordset ' Late Binding for Word ' For Early Binding: Microsoft Word #.# Object Library Dim oWord As Object 'Word.Application Dim oDoc As Object 'Word.Document Dim oTable As Object 'Word.Table Dim oRange As Object 'Word.Range 'variables Dim sMsg As String 'message Dim sPath As String 'file path Dim sPathFile As String 'file path and file name Dim nRow As Long 'current row of table Dim nCol As Long 'current column of table Dim nRows As Long 'number of data rows Dim nColumns As Long 'number of columns Dim i As Integer 'integer for counting Dim bCloseWord As Boolean 'True to close Word Application 'setup error handler On Error GoTo Proc_Err 'make sure we can open the query nRows = 0 Set db = CurrentDb() On Error Resume Next 'OpenRecordset using Snapshot: loads completely and is read-only Set rs = db.OpenRecordset(psQueryName,dbOpenSnapshot) If Err.Number > 0 Then sMsg = "Can't open query: " _ & vbCrLf & Space(5) & psQueryName MsgBox sMsg,, "Can't write results to Word " GoTo Proc_Exit End If On Error GoTo Proc_Err 'Count the rows and columns if not at end 'EOF stands for End Of File even though its not a traditional file With rs If Not .EOF Then ' no need to move with Snapshot '.MoveLast 'dynaset must load all to get RecordCount '.MoveFirst 'go back to start nRows = .RecordCount nColumns = .Fields.Count End If End With If Not nRows > 0 Then MsgBox "No records in query: " & psQueryName _ ,, "Can't write results to a Word document" GoTo Proc_Exit End If '-------------------------------------------- Status Bar sMsg = "Creating Word document ..." Application.SysCmd acSysCmdSetStatus,sMsg '-------------------------------------------- Document path ' CUSTOMIZE 'Path: QUERY_WordDocuments under database folder sPath = CurrentProject.Path & "\QUERY_WordDocuments\" 'create path if it doesn't exist If Dir(sPath,vbDirectory) = "" Then MkDir sPath DoEvents End If '-------------------------------------------- Document name sPathFile = sPath & "QUERY_" _ & psQueryName _ & Format(Now, "_yymmdd_hhnn") _ & ".DOCX" '-------------------------------------------- Word Application 'if Word is already open, use that instance 'ignore errors because if Word is NOT open, we will get one On Error Resume Next 'make assumption that Word is Open bCloseWord = False Set oWord = GetObject(, "Word.Application") On Error GoTo Proc_Err 'If oWord doesn't have a value then we need to open Word If oWord Is Nothing Then 'Word was not open -- create a new instance Set oWord = CreateObject( "Word.Application") bCloseWord = True End If '-------------------------------------------- New Word Document 'make a new Word Document Set oDoc = oWord.Documents.Add '-------------------------------------------- Setup Word With oDoc 'do page setup before writing data for better layout With .PageSetup '0=Portait, 1=Landscape .Orientation = piOrientation If pbNarrow <> False Then 'Narrow Margins 'distance in points (1"=72 points) .LeftMargin = 36 .RightMargin = 36 .TopMargin = 36 .BottomMargin = 36 End If End With 'PageSetup 'redefine Styles for document With .Styles( "Normal") 'only change in this document, not template .AutomaticallyUpdate = False With .ParagraphFormat .SpaceBefore = 2 'points, 72 points/inch .SpaceAfter = 2 .KeepTogether = True .LineSpacingRule = 0 'wdLineSpaceSingle End With 'ParagraphFormat End With 'Normal Style With .Styles( "Heading 1") .AutomaticallyUpdate = False With .ParagraphFormat .SpaceBefore = 0 .SpaceAfter = 4 End With 'ParagraphFormat End With 'Heading 1 Style '----------------------------------------- Content With .Content 'Title .InsertAfter psQueryName & ", " _ & Format(Now(), "yymmdd hh:nn ") 'style as Heading 1, .Parent is oDoc .Paragraphs(1).Style _ = .Parent.Styles( "Heading 1") .InsertParagraphAfter 'paragraph mark 'write description paragraph If psDescription <> "" Then .InsertAfter psDescription 'blank line .InsertParagraphAfter End If End With '----------------------------------------- Make table 'range for table, put at end Set oRange = .Content oRange.Collapse Direction:=0 'wdCollapseEnd 'insert table +1 row for header row Set oTable = .Tables.Add( _ Range:=oRange _ ,NumRows:=nRows + 1 _ ,NumColumns:=nColumns _ ) End With 'oDoc.Content '-------------------------------------------- Data With oTable 'column headings -- use query field names nRow = 1 For nCol = 1 To nColumns .Cell(nRow,nCol).Range.Text = rs.Fields(nCol - 1).Name Next nCol 'mark heading row .Rows(1).HeadingFormat = True 'dont allow rows to break .Rows.AllowBreakAcrossPages = False '----------------------------------------- Rows Do While Not rs.EOF sMsg = "Writing Row " & nRow & " of " & nRows Application.SysCmd acSysCmdSetStatus,sMsg nRow = nRow + 1 For nCol = 1 To nColumns .Cell(nRow,nCol).Range.Text = rs.Fields(nCol - 1).Value & "" Next nCol rs.MoveNext Loop 'rs 'best-fit columns .Columns.AutoFit '----------------------------------------- Border lines For i = 1 To 6 'wdBorderTop =-1 'wdBorderLeft = -2 'wdBorderBottom =-3 'wdBorderRight= -4 'wdBorderHorizontal = -5 'wdBorderVertical = -6 With .Borders(-i) .LineStyle = 1 'wdLineStyleSingle=1 .LineWidth = 8 'wdLineWidth100pt=8. wdLineWidth150pt=12 .Color = RGB(200,200,200) 'medium-light gray End With Next i 'change border lines to black for first row + add shading With .Rows(1) For i = 1 To 4 With .Borders(-i) .Color = 0 'wdColorBlack = 0 End With Next i 'Shading for header row, light-gray .Shading.BackgroundPatternColor = RGB(232,232,232) End With 'first row End With '-------------------------------------------- Header ' add after data and update page count Set oRange = oDoc.Sections(1).Headers(1).Range ' With oRange 'insert text of Heading 1 style 'wdFieldEmpty = -1 .Fields.Add Range:=.Characters.Last _ ,Type:=-1 _ ,Text:= "STYLEREF ""Heading 1"" " _ ,PreserveFormatting:=False 'then a TAB and text on right .InsertAfter Chr(9) _ & Format(Date, "d-mmm-yy, ddd") _ & ", page " 'then PAGE/NUMPAGES '33=wdFieldPage 'wdFieldEmpty = -1 .Fields.Add Range:=.Characters.Last _ ,Type:=-1 _ ,Text:= "PAGE" ' .InsertAfter Text:= "/" '26=wdFieldNumPages .Fields.Add Range:=.Characters.Last _ ,Type:=-1 _ ,Text:= "NUMPAGES" 'add border line below With .Borders(-3) 'wdBorderBottom =-3 .LineStyle = 1 'wdLineStyleSingle=1 .LineWidth = 8 'wdLineWidth100pt=8 .Color = RGB(75,75,75) 'dark gray End With With .ParagraphFormat 'clear current tabstops .TabStops.ClearAll 'set right-aligned Tab Stop at 10 inches '72 points/inch 'when Position > width, Word displays ok anyway '2=wdAlignTabRight '0=wdTabLeaderSpaces .TabStops.Add _ Position:=10 * 72 _ ,Alignment:=2 _ ,Leader:=0 '0=Left, 1=Center, 2=Right .Alignment = 0 '0=wdAlignParagraphLeft 'space after paragraph = 6 points .SpaceAfter = 6 End With .Fields.Update End With 'header '-------------------------------------------- Save File 'delete the output file if it already exists 'not likely as yymmdd_hhnn in filename If Dir(sPathFile) <> "" Then Kill sPathFile DoEvents End If 'save Word Document and Close With oDoc .SaveAs sPathFile .Close End With sMsg = "Created " & sPathFile Application.SysCmd acSysCmdSetStatus,sMsg sMsg = "Done creating a new Word document" _ & vbCrLf & " " & sPathFile Debug.Print Now(),sMsg sMsg = sMsg & vbCrLf & vbCrLf & "Open Path?" If MsgBox(sMsg,vbYesNo, "Done") <> vbNo Then 'open path Call Shell( "Explorer.exe " & sPath,vbNormalFocus) End If '-------------------------------------------- Exit Proc_Exit: On Error Resume Next If Not rs Is Nothing Then rs.Close Set rs = Nothing End If Set db = Nothing Set oRange = Nothing Set oTable = Nothing Set oDoc = Nothing If bCloseWord <> False Then oWord.Quit End If Set oWord = Nothing Application.SysCmd acSysCmdClearStatus Exit Sub Proc_Err: MsgBox Err.Description _ ,, "ERROR " & Err.Number _ & " aWordDocumentFromQuery" Resume Proc_Exit Resume End Sub '========================================================================== TEST '------------------------------------------------------------------------------- ' test_aWordDocumentFromQuery_SpecialChar '------------------------------------------------------------------------------- Public Sub test_aWordDocumentFromQuery_SpecialChar() '261007 'CLICK HERE, press F5 to Run! Dim sQueryName As String _ ,sDescription As String sQueryName = "qWdSpecialCharNotation" sDescription = "Notation for special characters that you can use when you" _ & vbCr & " Find or Find/Replace in Word," _ & vbLf & " including non-printing characters." _ & vbCrLf 'Create Word document Call aWordDocumentFromQuery(sQueryName,sDescription) End Sub '------------------------------------------------------------------------------- ' test_aWordDocumentFromQuery_Element '------------------------------------------------------------------------------- Public Sub test_aWordDocumentFromQuery_Element() '261007 'CLICK HERE, press F5 to Run! Dim sQueryName As String _ ,sDescription As String sQueryName = "qElement" sDescription = "Elements that all matter is composed of with" _ & " Element name, Symbol, Z, relative atomic Mass," _ & " Abundance (% in Body, Galaxy, and Air)," _ & " Essential? (subjective), Pronounciation, common Charges, " _ & " Group, and Period." _ & vbCrLf _ & "Sorted by Atomic Number (Z)," _ & " which is the number of protons in the nucleus of an atom." _ & vbCrLf 'Create Word document 'Landscape (wide), Narrow margins Call aWordDocumentFromQuery(sQueryName _ ,sDescription _ ,1,True) End Sub '------------------------------------------------------------------------------- ' test_aWordDocumentFromQuery_BogusError '------------------------------------------------------------------------------- Public Sub test_aWordDocumentFromQuery_BogusError() '260930 'CLICK HERE, press F5 to Run! Dim sQueryName As String _ ,sDescription As String sQueryName = "Bogus Query name" 'Create Word document -- error since query doesn't exist Call aWordDocumentFromQuery(sQueryName,sDescription) End Sub '------------------------------------------------------------------------------- ' test_aWordDocumentFromQuery_NoRecordsError '------------------------------------------------------------------------------- Public Sub test_aWordDocumentFromQuery_NoRecordsError() '260930 'CLICK HERE, press F5 to Run! Dim sQueryName As String _ ,sDescription As String sQueryName = "qNoRecords" 'Query doesn't have records 'Create Word document -- error since query doesn't have records Call aWordDocumentFromQuery(sQueryName,sDescription) End Sub '------------------------------------------------------------------------------- ' test_aWordDocumentFromQuery_CantOpenError '------------------------------------------------------------------------------- Public Sub test_aWordDocumentFromQuery_CantOpenError() '261010 'CLICK HERE, press F5 to Run! Dim sQueryName As String _ ,sDescription As String sQueryName = "qTempBadName" 'Query has a bad field name 'Create Word document -- error since query can't open Call aWordDocumentFromQuery(sQueryName,sDescription) End Sub '*************** Code End *******************************************************Code was generated with colors using the free Color Code add-in, runs in Access
Range.InsertAfter method (Word)
Range.InsertParagraphAfter method (Word)
Row.HeadingFormat property (Word)
Row.AllowBreakAcrossPages property (Word)
Range.ParagraphFormat property (Word)
Database.OpenRecordset method (DAO)
RecordsetTypeEnum enumeration (DAO)
TableDef.Fields property (DAO)
This is a good example of creating a Word document from data in Access. In this case, the data is the results of a query. Instead of calling routines as I usually do to make a new Word document, create a Word table with borders and shading, add a header, change orientation to Landscape and set narrow page margins, all the VBA code is in one procedure.
~ crystal
the simplest way is best, but usually the hardest to see