none
Serienbriefe: Word 2010 hat keinen Zugriff auf Access 2010 Formulare, die berechnete Daten enthalten RRS feed

  • Frage

  • Hallo Experte,

    Mein Problem ist, dass ich Adressen teilweise mit mehreren Empfängern brauche: z.B. Herr Xxxx Yyyy & Frau Zzzz Yyyy / Strasse / Stadt. In meiner Datenbank sind dabei Herr Xxxx Yyyy und Frau Zzzz Yyyy einzeln aufgeführt, da sie unterschiedlichen Status haben (z.B. ist Frau Zzzz Yyyy Ehrenmitglied und bezahlt nichts).

    In Access 2010 selbst ist das kein Problem: in der Adressen-Abfrage kann ich ein berechnetes Feld zufügen [ MyResult: =Partner([Diese_Person]) ]. Das funktioniert einwandfrei, MyResult enthält die gewünschten Zweitnamen:
         Function Partner(Mitglied) As Variant
              Dim DB As Database, AT As Recordset
              Set DB = CurrentDb()
              Set AT = DB.OpenRecordset("SELECT * FROM Mitglieder WHERE [Nº] = " & Mitglied & ";", dbOpenDynaset)
              Partner = ""
              While Not AT.EOF
                  Partner = Partner & vbNewLine & AT![Anrede] & " " & AT![Vorname] & " " & AT![Nachname]
                  AT.MoveNext
              Wend
         End Function

    Jedoch will Word 2010 davon nichts wissen: sobald eine Abfrage solch ein berechnetes Zusatzfeld enthält (auch mit Wert Null), wird sie als Datenquelle völlig unbrauchbar und gar nicht erst eingebunden. Versucht man diese wieder neu einzubinden, geschieht nichts; über den komplizierteren Weg (DB.accdc ausdrücklich über ODBC wählen, wobei die DB zunächst wegen der Endung .accdb nicht gefunden wird) erscheint die Fehlermeldung: "Word konnte die Datenquelle nicht öffnen".

    Wird der berechnete Parameter MyResult in Access 2010 wieder gelöscht (das passiert automatisch, wenn man das Kreuz bei Anzeigen entfernt), so funktioniert wieder der Zugriff aus Word 2010.

    Deshalb versuchte ich, die gewünschten Daten in einer Hilfstabelle zu speichern, die mit einer Abfrage erstellt werden kann und in der Adressen-Abfrage ebenfalls eingebunden ist. Das funktioniert, ist jedoch unschön (enthält redundante Daten) und problematisch, da sie nicht automatisch aktualisiert wird.

    Leider gibt es meines Wissens bei Abfragen jedoch keine Möglichkeit, Code auszuführen (z.B. Autorun- oder Autoopen-Funktionen), der diese Hilfstabelle jedesmal bei Bedarf neu erstellen oder aktualisieren kann. Word kann auch keine Formulare oder Berichte als Datenquellen nützen. Das Problem sollte also in Word selbst gelöst werden – nur habe ich keine Ahnung, wie ? Kann man obere Funktion so umschreiben, dass sie in Word funktioniert ?

    Das Problem ist schon einmal aufgetaucht (vgl. Word Serienbrief aus Access ), die vorgeschlagene Lösung funktioniert bei mir nicht: Word 2010 listet Tabellenerstellungsabfragen gar nicht als mögliche Datenquellen auf ! Mir scheint, Word holt sich nur SQL-Code von Access, das geht nur mit einfachsten Abfragen.

    Besten Dank im Voraus für nützliche Tipps

    Samstag, 28. September 2013 09:13

Alle Antworten

  • Zur Info: ich konnte das Problem folgendermassen lösen

    (sehr umständlich und aufwändig, aber es läuft zufriedenstellend…):

    In Word 2010 ×64 :

    Private Declare PtrSafe Function ShowWindow Lib "user32" (ByVal hwnd As Long, _ ByVal nCmdShow As Long) As Long ' Notwendig für die Funktion ShowWindow() Sub Autonew() ' ' Work-around, da Word keinen Zugriff auf Abfragen mit Funktionen hat ' Access-Funktion => Partner: Partner_finden([Mitglieder]![OG-Nº]) ' NB: auch nicht über SQL => Partner_finden([OG-Nº]) AS Partner ' NB: die SQL-Befehle in in Word und in der Access-Abfrage sind unterschiedlich ! ' z.B. JOIN + ORDER sind nur in der Access-Abfrage vorhanden ' Dim DB_Pfad As String, DB_Name As String, DB_Voll As String, _ Doc_Pfad As String, Doc_Name As String, Doc_Titel As String, _ Vor_Pfad As String, Vor_Name As String, TmpTab As String, TmpAbfr As String Dim AccessObj As Object, Access_da As Boolean, AccWin As Long, Success As Long ' ' Name der temporären Tabelle und Abfrage festlegen ' TmpTab = "Tmp" & Format(Now, "yyyymmddhhmmss") TmpAbfr = "Wrd" & Format(Now, "yyyymmddhhmmss") ' ' Name des aufrufenden Dokumentes eruieren ' Vor_Pfad = ActiveDocument.AttachedTemplate.Path ' Vorlagepfad Vor_Name = ActiveDocument.AttachedTemplate ' Vorlagename Doc_Pfad = ActiveDocument.Path ' Dateipfad Doc_Name = ActiveDocument.Name ' Dateiname Doc_Titel = Windows(ActiveDocument.ActiveWindow) ' Fenstername (ggfs. inkl. […] […]) ' ' Dokument mit Datenbank-Angaben konsultieren ' Documents.Open FileName:=Vor_Pfad & "\Wordparameter.doc", ConfirmConversions:=True, _ ReadOnly:=True, Visible:=False, AddToRecentFiles:=False, PasswordDocument:="", _ PasswordTemplate:="", Revert:=True, WritePasswordDocument:="", _ WritePasswordTemplate:="", Format:=wdOpenFormatAuto, XMLTransform:="" Windows("Wordparameter.doc [Schreibgeschützt] [Kompatibilitätsmodus]").Activate Selection.GoTo What:=wdGoToBookmark, Name:="db_Pfad" Selection.MoveRight Unit:=wdCell DB_Pfad = Selection.Text If Right(DB_Pfad, 1) = "\" Then DB_Pfad = Left(DB_Pfad, Len(DB_Pfad) - 1) Selection.GoTo What:=wdGoToBookmark, Name:="db_Name" Selection.MoveRight Unit:=wdCell DB_Name = Selection.Text Selection.MoveRight Unit:=wdCell DB_Name = DB_Name & Selection.Text DB_Voll = DB_Pfad & "\" & DB_Name Windows("Wordparameter.doc [Schreibgeschützt] [Kompatibilitätsmodus]").Close Selection.HomeKey Unit:=wdStory ' ' temporäre Tabelle in der DB erzeugen ' On Error Resume Next ' Fehler, falls Access nicht läuft Set AccessObj = GetObject(, "Access.application") If Err.Number <> 0 Then ' Access läuft nicht Access_da = False Else Access_da = True End If Err.Clear On Error GoTo 0 ' Fehlerbehandlung wieder einschalten Set AccessObj = GetObject(DB_Voll) ' Aktiviert die Datenbank, auch wenn Access vorher nicht lief TmpTab = "Tmp" & Format(Now, "yyyymmddhhmmss") ' Eindeutiger Name für die temporäre Tabelle AccWin = AccessObj.Application.hWndAccessApp ' Fenster-Handle ermitteln Success = ShowWindow(ByVal AccWin, ByVal 0) ' Fenster ausblenden 'Debug.Print Success & " : " & AccessObj.Application.Visible ' ´0 : Wahr´ (!), obwohl Access-Fenster wie erwünscht unsichtbar With AccessObj '.Application.Visible = False ' ******* = Fehler ******* .Run "CreateTemporäreWordTabelle", TmpTab .Run "CreateTemporäreWordAbfrage", TmpAbfr, TmpTab End With ' ' nun temporäre Datenbank und temporäre Abfrage einbinden ' Windows(Doc_Titel).SetFocus ActiveDocument.MailMerge.OpenDataSource Name:=DB_Voll, ConfirmConversions:=False, _ ReadOnly:=False, LinkToSource:=True, AddToRecentFiles:=False, PasswordDocument:="", _ PasswordTemplate:="", WritePasswordDocument:="", WritePasswordTemplate:="", _ Revert:=False, Format:=wdOpenFormatAuto, Connection:="DSN=MS Access Database;DBQ=" _ & DB_Voll & ";" & "DefaultDir=" & DB_Pfad & ";DriverId=25;FIL=MS Access;" _ & "MaxBufferSize=2048;PageTimeout=5;UID=admin;", SQLStatement:= _ "SELECT Mitglieder.[Haupt-Nº], Mitglieder.[Anrede], Mitglieder.[Vorname], " _ & "Mitglieder.[Nachname], Mitglieder.[Adresse], Mitglieder.[PLZ], " _ & "Mitglieder.[Ort], " & TmpTab & ".[OG-Nº], " & TmpTab & ".[Partner]" _ & " FROM " & TmpAbfr, SQLStatement1:="", SubType:=wdMergeSubTypeOther ' ' Sendungen fertigstellen und zusammenführen ' With ActiveDocument.MailMerge .Destination = wdSendToNewDocument ' wdSendToNewDocument=0, wdSendToPrinter=1, wdSendToEmail=2, wdSendToFax=3 .SuppressBlankLines = True With .DataSource .FirstRecord = wdDefaultFirstRecord .LastRecord = wdDefaultLastRecord End With .Execute Pause:=False End With ' ' Access in den vorherigen Zustand versetzen ' ' Die in Word eingebundene temporäre Tabelle ist gesperrt und muss ' zuerst durch Wahl einer anderen, permanenten Tabelle freigegeben werden ! ActiveDocument.MailMerge.OpenDataSource Name:=DB_Voll, ConfirmConversions:=False, _ ReadOnly:=False, LinkToSource:=True, AddToRecentFiles:=False, PasswordDocument:="", _ PasswordTemplate:="", WritePasswordDocument:="", WritePasswordTemplate:="", _ Revert:=False, Format:=wdOpenFormatAuto, Connection:="DSN=MS Access Database;DBQ=" _ & DB_Voll & ";" & "DefaultDir=" & DB_Pfad & ";DriverId=25;FIL=MS Access;" _ & "MaxBufferSize=2048;PageTimeout=5;UID=admin;", SQLStatement:="SELECT * FROM " _ & "`Adressen (ohne DM)`", SQLStatement1:="", SubType:=wdMergeSubTypeOther AccessObj.Run "DeleteTemporäreObjekte", TmpAbfr, TmpTab If Access_da = False Then ' Access lief vorher nicht AccessObj.Application.Quit Else 'AccessObj.Application.Visible = True '******* = Fehler ******* Success = ShowWindow(ByVal AccWin, ByVal 1) ' Fenster einblenden 'Debug.Print Success & " : " & AccessObj.Application.Visible ' ´0 : Wahr´ , Access-Fenster wieder sichtbar End If Set AccessObj = Nothing ' Verweis auf Anwendung und DB freigeben ' ' Aufrufendes Dokument schliessen ' Windows(Doc_Titel).Close wdDoNotSaveChanges End Sub

    Konterpart in Access 2010 ×64 :

    Option Compare Database
    
    Sub CreateTemporäreWordTabelle(T_Name)
    
        Dim DB As Database, AT As Recordset, BT As Recordset, CT As Recordset, Partner As String
        Set DB = CurrentDb()
        '
        ' Neue, temporäre Tabelle erzeugen
        '
        Set Tdb = DB.CreateTableDef(T_Name)
        Set TF = Tdb.CreateField("OG-Nº")
            TF.Type = dbLong
            TF.Attributes = dbAutoIncrField
        Tdb.Fields.Append TF
        ' Code der MS Office-Hilfe versagt bei mehreren Felder gleichzeitig
        Set TF = Tdb.CreateField("Partner")
            TF.Type = dbText
            TF.Size = 255                    ' > 255 geht leider nicht…
        Tdb.Fields.Append TF
        DB.TableDefs.Append Tdb
        Application.RefreshDatabaseWindow
        '
        ' Nun Datensätze mit Partnern einfüllen
        '
        Set AT = DB.OpenRecordset("SELECT * FROM Mitglieder WHERE [Haupt-Nº] Is Null;", dbOpenDynaset)
        Partner = ""
        While Not AT.EOF
            Set BT = DB.OpenRecordset("SELECT * FROM Mitglieder WHERE [Haupt-Nº] = " _
                 & AT![OG-Nº] & ";", dbOpenDynaset)
            Partner = ""
            While Not BT.EOF
                Partner = Partner & vbNewLine _
                    & BT![Anrede] & " " & BT![Vorname] & " " & BT![Nachname]
                BT.Edit
                If Len(Partner) > 255 Then Partner = Left(Partner, 255)
                ' Die Feldlänge in der Tabelle ist maximal 255
                Set CT = DB.OpenRecordset("SELECT * FROM " & T_Name & ";", dbOpenDynaset)
                CT.AddNew
                CT![OG-Nº] = AT![OG-Nº]     ' INSERT INTO funktioniert anscheinend nicht
                CT![Partner] = Partner
                CT.Update
                BT.MoveNext
            Wend
            BT.Close
            AT.MoveNext
        Wend
    
    End Sub
    
    
    Sub CreateTemporäreWordAbfrage(TmpAbfr, TmpTab)
    
        Dim DB As Database, WrdTmp As QueryDef
        Set DB = CurrentDb()
        Set WrdTmp = DB.CreateQueryDef(TmpAbfr, _
              "SELECT Mitglieder.[Haupt-Nº], Mitglieder.Anrede, Mitglieder.Vorname, " _
              & "Mitglieder.Nachname, Mitglieder.Adresse, Mitglieder.PLZ, Mitglieder.Ort, " _
              & TmpTab & ".Partner, " & TmpTab & ".[OG-Nº] FROM Mitglieder LEFT JOIN " & TmpTab _
              & " ON Mitglieder.[OG-Nº] = " & TmpTab & ".[OG-Nº] WHERE (((Mitglieder.[Haupt-Nº]) " _
              & "Is Null)) ORDER BY Mitglieder.Nachname;")
        Application.RefreshDatabaseWindow
    
    End Sub
    
    
    Sub DeleteTemporäreObjekte(TmpAbfr, TmpTab)
    
        Dim DB As Database
        Set DB = CurrentDb()
        With DB
           .QueryDefs.Delete TmpAbfr
           '.TableDefs.Delete TmpTab
           .Close
        End With
        Application.RefreshDatabaseWindow
    
    
    End Sub
    
    Vielleicht weiss jemand, wie das einfacher geht ?

    Dienstag, 1. Oktober 2013 15:02