Access 2010 SQL-data overzetten naar tabel in Word 2010

Status
Niet open voor verdere reacties.

L1NKKUN

Nieuwe gebruiker
Lid geworden
18 mrt 2011
Berichten
3
Hey allemaal,

Ik ben deze week beziggeweest met het maken van een access database voor op onze afdeling. De database bestaat uit een formulier om data toe te voegen (verder niet zo heel spannend).

Mijn idee is nu om aan de hand van een knop in Access een SQL query te draaien (even simpel: SELECT * FROM Deployments ORDER BY ID DESC) en deze via een recordset overzetten naar een bestaand Word-document. Dit lukt allemaal door de tabel in mijn document te voorzien van fields.

Het probleem is nu: de recordset plaats enkel de eerste rij in mijn tabel in Word, terwijl er - momenteel - twee testrijen in de database staan.

Mijn vraag is: hoe zorg je ervoor dat je via VBA in Access een nieuwe rij aan de tabel in Word laat toevoegen wanneer er meer dan een één record opgevraagd wordt vanuit de query?

Ik heb nu dit (je zou zeggen: via de loop met rs.MoveNext moet de code de volgende regel pakken).

Code:
Private Sub reportQuery1_Click()

'Define variables
Dim dbs As DAO.Database
Dim rs As DAO.Recordset
Dim WordApp As Word.Application
Dim doc As Word.Document
Dim strSql As String
Dim fld1, fld2, fld3, fld4, fld5, fld6, fld7 As Field

'Avoid error and set Word object variable
On Error Resume Next
Set WordApp = GetObject(, "Word.Application")
    If Err = 429 Then
        Set WordApp = New Word.Application
        Err = 0
    End If

'Set the database
Set dbs = CurrentDb()
strSql = "SELECT * FROM Deployments ORDER BY ID DESC"

'Set the recordset
Set rs = dbs.OpenRecordset(strSql)
Set fld1 = rs.Fields(1)
Set fld2 = rs.Fields(2)
Set fld3 = rs.Fields(3)
Set fld4 = rs.Fields(4)
Set fld5 = rs.Fields(5)
Set fld6 = rs.Fields(6)
Set fld7 = rs.Fields(7)

'Cycle through records to fill Word form fields
Do While Not rs.EOF

    'Set path to document
    Set doc = WordApp.Documents.Open("D:\users\mazijkde\Desktop\template.docx", , True)

    'Print data to fields in Word
    With doc
        .FormFields("fldInsertDate").Result = fld1.Value
        .FormFields("fldQaEnv").Result = fld2.Value
        .FormFields("fldAdapter").Result = fld3.Value
        .FormFields("fldEnvironment").Result = fld4.Value
        .FormFields("fldConfiguration").Result = fld5.Value
        .FormFields("fldActiveDate").Result = fld6.Value
        .FormFields("fldActiveTime").Result = fld7.Value
        .Visible = True
        .Activate
    rs.MoveNext
    End With
Loop

'Unset Word application
Set doc = Nothing
Set WordApp = Nothing
Exit Sub

'Error handling
errHandler:
MsgBox Err.Number & ": " & Err.Description

End Sub
 
Waarom maak je geen Samenvoegdocument in Word, waarin je een Catalogus maakt? Dat samenvoegmodel is ontworpen om het door jou gewenste document te genereren. Je koppelt hem aan je Access tabel of query, en je bent klaar...
Overigens heb je een beetje vreemde manier van velden declareren; alleen het laatste veld is gedefinieerd als veld, de rest is nu van het type Variant. Wil je alle velden als velden, dan moet dat zo:

Code:
Dim fld1 As Field, fld2 As Field, fld3 As Field, fld4 As Field, fld5 As Field, fld6 As Field, fld7 As Field
 
Hoi L1nkKUN,

Ik weet het niet zeker, maar ik denk dat het door je code komt
om dat te testen eerst maar even de boel rechtzettten


Ik weet niet of wanneer je een specifiek veld van een recordset aan een variabele toewijst, wat er dan met die verwijzing gebeurt als je in je recordset naar de volgende rij gaat.

Ik denk dat je het declareren van de velden van de recordset sowieso beter achterwege kunt laten, omdat je bij het veranderen van het aantal velden in de query, je code vele malen makkelijker is aan te passen ([tabel verwijzing in word]=[recordset.field(X)]

Dus sla die variabelen over en vul de velden in je word document direct met de fields uit de recordset.

Ook miste ik een on error goto ErrHandler: // errorclear bij het niet optreden van een fout na je on error resume next.( die wel gebruikelijk is als je een word.application zoekt.), plus de vraag wat je doet met je word/dao objecten bij het optreden van een fout.

Verder nog even je recordset en je daoconnectie opruimen, en dan kunnen we eens kijken wat er nu met de code gebeurt.

Succes,
Mark.

Aangepaste code:
Code:
Private Sub reportQuery1_Click()
'Define variables
Dim dbs As DAO.Database
Dim rs As DAO.Recordset
Dim WordApp As Word.Application
Dim doc As Word.Document
Dim strSql As String

'Avoid error and set Word object variable
On Error Resume Next
Set WordApp = GetObject(, "Word.Application")
    If Err = 429 Then
        Set WordApp = New Word.Application
        Err = 0
    End If

On Error GoTo errHandler:

'Set the database
Set dbs = CurrentDb()
strSql = "SELECT * FROM Deployments ORDER BY ID DESC"

'Set the recordset
Set rs = dbs.OpenRecordset(strSql)

'Cycle through records to fill Word form fields
Do While Not rs.EOF

    'Set path to document
    Set doc = WordApp.Documents.Open("D:\users\mazijkde\Desktop\template.docx", , True)

    'Print data to fields in Word
    With doc
        .FormFields("fldInsertDate").Result = rs.Fields(1)
        .FormFields("fldQaEnv").Result = rs.Fields(2)
        .FormFields("fldAdapter").Result = rs.Fields(3)
        .FormFields("fldEnvironment").Result = rs.Fields(4)
        .FormFields("fldConfiguration").Result = rs.Fields(5)
        .FormFields("fldActiveDate").Result = rs.Fields(6)
        .FormFields("fldActiveTime").Result = rs.Fields(7)
        .Visible = True
        .Activate
    End With
    
    rs.MoveNext
    
Loop

On Error GoTo 0
'Error handling
errHandler:

If Err.Number <> 0 Then
    MsgBox Err.Number & ": " & Err.Description
End If

'Unset Word application
Set doc = Nothing
Set WordApp = Nothing
Set dbs = Nothing
Set rs = Nothing

End Sub
 
Laatst bewerkt:
Het aanpassen van de recordsetcode zal niet zo heel veel helpen; het grootste probleem is dat de code wel door de recordset loopt, maar de waarden uit die recordset steeds op dezelfde plek neerzet. TS heeft in zijn Word document een aantal velden gemaakt, die hij wil vullen. Hij vergeet daarbij dat één veld slechts gevuld kan worden met één waarde: ik zou dus eigenlijk verwachten dat het eindresultaat niet één rij met waarden uit de eerste rij van de query is, maar een gevulde rij met de waarden uit het laatste record. Dit omdat de loop logischerwijs begint met het inlezen van het eerste record, om dan die waarden in de Word velden te zetten, waarna het volgende record hetzelfde doet, namelijk dezelfde velden opnieuw vullen. Hoe je het ook wendt of keert: het eindresultaat zal altijd één regel met waarden zijn. Vandaar mijn oplossing via een samenvoeg document van het type Catalogus. Ook daarin gebruik je velden uit de query, maar bij het samenvoegen wordt voor elk record een eigen regel gemaakt voor elk record. En het mooie is ook nog eens, dat je er geen regel voor hoeft te programmeren....
 
Buiten dat de oorspronkelijke code van TS bij elk record de veldwaarden overschrijft met die van het volgende record, wordt ook nog eens voor elk record in de query het document opnieuw geopend. Dat zou nog geen probleem hoeven te zijn als het document daarna wordt opgeslagen en gesloten, maar dat is ook niet het geval.

Om een methode te laten zien waarbij je de records als regels in een document krijgt, kun je deze code gebruiken.

Code:
Set dbs = CurrentDb()                                   'Set the database
strSql = "SELECT * FROM [qZaalreserveringen Politiek]"

Set doc = WordApp.Documents.Open("H:\test.doc", , True) 'Set path to document
doc.Visible = True

Set rs = dbs.OpenRecordset(strSql)                      'Set the recordset
Do While Not rs.EOF                                     'Cycle through records to fill Word form fields
    With doc                                            'Print data in Word
        Selection.TypeText Text:=rs.Fields(1) & vbTab
        Selection.TypeText Text:=rs.Fields(2) & vbTab
        Selection.TypeText Text:=rs.Fields(3) & vbTab
        Selection.TypeText Text:=rs.Fields(4) & vbTab
        Selection.TypeText Text:=rs.Fields(5) & vbTab
        Selection.TypeText Text:=rs.Fields(6) & vbTab
        Selection.TypeText Text:=rs.Fields(7) & Chr(11)
    End With
    rs.MoveNext
Loop
Selection.TypeBackspace
Selection.TypeParagraph

MsgBox "Alle records zijn overgetypt..."

Zoals je kunt zien wordt hier het document één keer geopend, en wordt daarna van elk record de veldwaarde in het document getypt. Als laatste kun je het Word document dan nog opslaan, en bewaren.
 
Ik heb nog eens goed gelezen en ik snap ook niet waarom TS de code in één tabel wil, maar wel voor elke record een nieuw document maakt.

Ik dacht eerst dat het probleem was dat de recordset dezelfde velden bleef vasthouden na movenext, maar nu weet ik het ook niet meer :)
 
Ik vermoed dat hij de code ergens van het internet heeft geplukt, maar de situatie waarin de code gebruikt wordt niet hetzelfde heeft opgezet. Met dus dit vreemde resultaat. Maar we wachten af wat hij nu te zeggen heeft :)
 
Oh, ik zie dat er ineens flink is gereageerd hier. Haha, dacht dat ik wel een mailtje zou krijgen met daarin een notificatie. Mijn excuses voor de late reactie dus, en bedankt voor de hulp dusver.

Ik heb momenteel het volgende gedaan :)

Deze functie gebruik ik om de data uit de query te halen en uit te printen op een rapport in Access. Ziet er allemaal erg mooi uit, en de PDF gaat verder ook goed. Probleem is dat ik het toch graag in een Word document zou willen zien. Waarom? De gebruiker heeft Word-documenten nodig en geen RTF of PDF. PDF is mooi, maar het kopiëren naar een Word-document wordt soms wat lastig. Ik wil namelijk de tabelopmaak behouden die ik in Access aan mijn rapport heb gekoppeld.

Code:
'Create function
Public Function printQueryResult(strSql As String)
On Error GoTo MyErrorHandler

    'Define variables
    Dim dbs As DAO.Database
    Dim rs As DAO.Recordset
    Dim qdf As QueryDef
    Dim sUniqueFileName As String
    
    Const myPath As String = "d:\users\mazijkde\Desktop"
    
    'Set default path
    ChDrive myPath
    ChDir myPath
    
    'Set the database and recordset
    Set dbs = CurrentDb()
    Set rs = dbs.OpenRecordset(strSql, dbOpenSnapshot)
    
    'Randomize number and create filename
    sUniqueFileName = Year(Now) & Rand(1, 99999) & ".pdf"
    
    If rs.RecordCount > 0 Then
    
        'Print the results of the query
        With dbs
        
            'Set temporary SQL table
            Set qdf = .CreateQueryDef("tmpQueryResults", strSql)

            'Add data to report
            .QueryDefs("tmpQueryResults").SQL = strSql
            DoCmd.OpenReport "QueryAdapterResults", acViewPreview
            .QueryDefs.Delete "tmpQueryResults"
            
        End With
    
        'Close temporary files
        dbs.Close
        qdf.Close
        
        'Close form
        DoCmd.Close acForm, "GetAdapterData", acNormal
        DoCmd.RunCommand acCmdZoom100
        
        'Message box to convert file to PDF
        If MsgBox("Would you like to convert this data to a PDF file?", vbYesNo, "Convert file to PDF") = vbYes Then
            DoCmd.OutputTo acOutputReport, "QueryAdapterResults", acFormatPDF, sUniqueFileName
            MsgBox "Data has been saved to " & myPath & " as a new PDF file."
        End If

    Else
        'No results found
        MsgBox "No results found."
        
    End If
   
'Error handler
MyErrorHandler:
    If Err.Number = 2501 Then
    End If
    
End Function

Deze code zorgt voor de verwerking van de query en al de data die is geselecteerd op het formulier. Je kunt een datum kiezen, velden selecteren in een listbox, etc.

Code:
Private Sub getQuery_Click()
On Error GoTo Err_getQuery_Click

    'Define variables
    Dim dtFrom As String
    Dim dtUntil As String
    Dim strQA As Variant
    Dim strSys As String
    Dim i As Long
    
    'Convert dates to string
    dtFrom = "#" & CDate(VBA.Format(Me.dateFrom.Value, "mm/dd/yy")) & "#"
    dtUntil = "#" & CDate(VBA.Format(Me.dateUntil.Value, "mm/dd/yy")) & "#"
    
    'Loop through listbox and check values
    For i = 0 To Me.getQAenvironments.ListCount - 1
        If Me.getQAenvironments.Selected(i) Then
            strQA = strQA & "'" & Me.getQAenvironments.Column(0, i) & "',"
        End If
    Next i
    
    For i = 0 To Me.getSystem.ListCount - 1
        If Me.getSystem.Selected(i) Then
            strSys = strSys & "'" & Me.getSystem.Column(0, i) & "',"
        End If
    Next i

        'Box selection true?
        If Me.boxSelection.Value = True Then
        
            'Get values from selection in fields
            printQueryResult "SELECT t.QaEnv, t.System, t.Type, MAX(t.Configuration) AS Configuration, MAX(t.ActiveDate) AS ActiveDate, t.ActiveTime FROM Deployments AS t WHERE t.ActiveDate >=" & dtFrom & _
            " AND t.ActiveDate <=" & dtUntil & " AND t.QaEnv IN " & "(" & Left(strQA, Len(strQA) - 1) & ") AND t.System IN " & "(" & Left(strSys, Len(strSys) - 1) & ") GROUP BY t.QaEnv, t.System, t.Type, t.ActiveTime;"
     
        Else
    
            'Get values from selection in fields
            printQueryResult "SELECT * FROM Deployments WHERE ActiveDate >=" & dtFrom & _
            " AND ActiveDate <=" & dtUntil & " AND QaEnv IN " & "(" & Left(strQA, Len(strQA) - 1) & ") AND System IN " & "(" & Left(strSys, Len(strSys) - 1) & ") ;"
            
            'Close form
            DoCmd.Close acForm, "GetAdapterData", acNormal
            
        End If

Exit_getQuery_Click:
    Exit Sub

Err_getQuery_Click:

    'Fields are empty; print message box
    If Err.Number = 5 Then
        MsgBox "You must make a selection from the list", , "Selection Required"
        Resume Exit_getQuery_Click
    Else
        'Write out the error and exit the sub
        MsgBox Err.Description
        Resume Exit_getQuery_Click
    End If
    
End Sub

En oh ja, ik gebruik altijd Engelse comments bij code =) ik heb wel wat opgezocht, maar voor de rest alles zelf in elkaar gezet.
 
Laatst bewerkt:
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan