Language: Deutsch English















Last Update: 2024 - 05 - 21








Wie man einen dynamisch gefilterten Access Bericht als PDF exportieren kann

von Philipp Stiefel, ursprünglich veröffentlicht 8. November 2017

letzte Überarbeitung am 2024-05-19


Access - Bericht zu PDF - Illustration

In Microsoft Access 2010 und neueren Versionen (in Access 2007 mit einen zusätzlichen Add-In) wurde die sehr nützliche Format-Option acFormatPDF der DoCmd.OutputTo-Methode ergänzt. Diese Option ermöglicht es dir einfach einen Access Report mit VBA Code, ohne Zusatzkomponenten, als PDF zu exportieren.

Ich sehe jedoch immer wieder, dass Leute mit einem Aspekt dieser sehr bequemen Methode zu kämpfen haben. Es ist nicht so intuitiv offensichtlich, wie man einen dynamisch gefilterten Bericht mit dieser Methode exportieren kann. Anders als die DoCmd.OpenReport-Methode unterstützt es die DoCmd.OutputTo-Methode nicht, Filterkriterien zu übergeben. Also scheint es problematisch zu sein, einen Bericht zu exportieren, der abhängig von Benutzereingaben oder anderen Faktoren, verschiedene Daten darstellt.

Üblicherweise kommt einem einer der folgenden, naheliegenden Workarounds in den Sinn.

  • Mehrere, verschiedene Berichte mit verschiedenen fest gespeicherten Kriterien zu erstellen.
  • Eine Parameterabfrage mit Bezug auf globale Funktionen oder Formularfelder.
  • Zur Laufzeit das SQL für den Bericht aufzubauen und dieses dem Bericht als Datenherkunft zuzuweisen.

All diese Workarounds funktionieren. Allerdings ist mit jedem der obigen Ansätze mindestens ein Nachteil verbunden. (Übereinstimmend mit der obigen Reihenfolge):

  • Erfordert es, mehrere, sehr ähnliche Berichte zu erstellen. – Ist sehr unflexibel und eine Last bei der Wartung.
  • Erfordert zusätzliche Funktionen/Formularfelder und ist auch eher unflexibel.
  • Erfordert es, die komplette Abfrage zur Laufzeit zu erstellen und sie dem Bericht im Report_Open-Ereignis als Datenquelle zuzuweisen. – Ein grundsätzlich akzeptables Vorgehen, aber für diesen Fall unnötig kompliziert, fehlerträchtig und generell unschön durch die externe (vom Bericht aus) Abhängigkeit der Definition der Datenquelle.

Zwar funktionieren all die obigen Workarounds, aber ich möchte keinen davon für unseren Zweck empfehlen.

Glücklicherweise gibt es eine sehr einfache Lösung für das Problem, die nur nicht so offensichtlich ist.

Wenn der Bericht, den du exportierst geschlossen ist, wenn du DoCmd.OutputTo aufrufst, dann wird die OutputTo-Methode den Bericht öffnen und ihn exportieren. – Ganz einfach. Das ist die Ursache für das ganze Problem.

Wenn allerdings der Bericht, den du exportierst, bereits in der Vorschau-Ansicht geöffnet ist, wenn du DoCmd.OutputTo aufrufst, dann wird die OutputTo-Methode den Bericht einfach so exportieren wie er ist.

Wenn man dies berücksichtig, ist es sehr einfach das Problem mit dem Export der dynamisch gefilterten Berichte zu lösen. Du öffnest den Bericht mit DoCmd.OpenReport in der Vorschau-Ansicht (View=acViewPreview) und übergibst deine dynamischen Filterkriterien an das WhereCondition-Argument der Methode. Um zu verhindern, dass der Bericht auf dem Bildschirm auftaucht, verwendest du den WindowMode acHidden, um den Bericht für den Benutzer unsichtbar zu öffnen.

Danach rufst du einfach DoCmd.OutputTo für das Format acFormatPDF und mit allen übrigen Argumenten wie zuvor auf.

Es gibt nur eine Sache, die du nicht vergessen darfst. Nachdem der Bericht in der Vorschau-Ansicht geöffnet wurde, bleibt er geöffnet, wenn auch unsichtbar, bis er explizit wieder geschlossen wird. Wenn du den Bericht erneut mit DoCmd.OpenReport „öffnest“ während er noch geöffnet ist, werden die zuvor verwendeten Filter nicht geändert und die Daten nicht aktualisiert. In diesem Fall wird der Bericht dann die alten, möglicherweise falschen Daten anzeigen. – Einfache Lösung: Schließe den versteckten Bericht immer, nachdem das PDF exportiert wurde.

Wenn wir all dies berücksichtigen, dann könnte unsere Prozedur zum Exportieren des gefilterten Berichts etwa so aussehen:

Public Sub ExportFilteredReportToPDF() Dim reportName As String Dim fileName As String Dim criteria As String reportName = "rptYourReportName" fileName = "C:\tmp\report_export_file.pdf" criteria = "SomeTextField = 'ABC' AND SomeNumberField = 123" DoCmd.OpenReport reportName, acViewPreview, , criteria, acHidden DoCmd.OutputTo acOutputReport, reportName, acFormatPDF, fileName DoCmd.Close acReport, reportName, acSaveNo End Sub

In einer echten Implementierung, basierend auf diesem Beispiel, kannst du alle drei Variablen als Argument der der Prozedur definieren und somit eine einfache und flexible ExportToPDF-Rountine für deine Access Anwendung erstellen.

Da wären wir also. Eine elegante, aber dennoch sehr einfach umzusetzende, Lösung die nur zwei zusätzliche Zeilen Code erfordert.

Add-On-Video: Gefilterten Access Bericht als PDF exportieren

Hier noch eine Ergänzung zu dem Artikel. Ich habe eine Demonstration dieses Lösungsweges auf Video aufgezeichnet und auf YouTube veröffentlicht.

Performance

Die oben erläuterte Lösung ist für die meisten Szenarien geeignet. Wenn du jedoch komplexe Berichte hast, die auf komplexen Abfragen basieren, oder wenn du eine große Anzahl von PDF-Dokumenten exportieren musst, wirst du möglicherweise feststellen, dass ein PDF-Export auf Basis dieser Lösung einige Zeit in Anspruch nimmt.

Leser Klaus Oberdalhoff berichtete von einem Fall, in dem beides zusammenkam. Er musste einen sehr komplexen Rechnungsbericht exportieren und bei jedem Exportlauf mussten Hunderte von PDF-Dateien generiert werden. Dieser Export dauerte mit der oben beschriebenen Technik etwa 3 Stunden. Um die Performance zu verbessern wandte er den dritten der oben genannten, nicht empfohlenen Ansätze an, indem er im Report_Open-Ereignis die Recordsource änderte, um das jeweils aktuelle Kriterium einzuschließen. Dadurch konnte er den Zeitaufwand für den PDF-Export auf nur noch 30 Minuten deutlich reduzieren.

Was verursacht dieses Performanceproblem?

Mein einfacher Vorschlag oben wird einmal die Daten abfragen und den Bericht rendern, wenn er unsichtbar in der Vorschau geöffnet wird, und dann noch einmal, wenn er als PDF exportiert wird.

Das Erstellen der PDF-Datei scheint weniger Ressourcen und Zeit zu verbrauchen als das Rendern der visuellen Berichtsvorschau. Der zusätzliche Aufwand beim Öffnen der Vorschau verdoppelt also nicht nur die benötigte Zeit, sondern verlängert sie um ein Vielfaches. – Um wieviel, hängt von der Komplexität des Berichts ab.

Wie können wir die Performance verbessern?

Ich habe oben zwei Alternativen genannt:

  • Eine Parameterabfrage mit Bezug auf globale Funktionen oder Formularfelder.
  • Zur Laufzeit das SQL für den Bericht aufzubauen und dieses dem Bericht als Datenherkunft zuzuweisen.

Wie oben erwähnt, funktionieren beide im Allgemeinen und beide wären geeignet, das Performanceproblem zu lösen. Dennoch sehe ich aus den oben genannten Gründen davon ab, sie zu empfehlen.

Es gibt noch eine weitere Option, die mir ebenfalls überhaupt nicht gefällt, die aber meiner Meinung nach das geringste Übel in diesem Szenario ist: TempVars.

Um TempVars als Abfragekriterien zu verwenden, musst du diese in den Entwurf der Abfrage integrieren. Wenn wir also dieselben Kriterien wie im obigen Beispiel verwenden möchten, müssen wir die Recordsource-Abfrage des Berichts in etwa so ändern:

SELECT * FROM OriginalReportDataSource WHERE SomeNumberField = [TempVars]![SomeNumberFieldCriteriaForPdfExport] AND SomeTextField = [TempVars]![SomeTextFieldCriteriaForPdfExport];

Um diesen Bericht mit den TempVar-Kriterien zum Erstellen der PDF-Dateien aus dem Bericht zu verwenden, müssen wir nun die TempVars auf die entsprechenden Werte setzen, bevor wir DoCmd.OutputTo aufrufen. Der folgende VBA-Code ist ein Beispiel für die Implementierung:

Public Sub ExportFilteredReportToPDF_UsingTempVars() Dim reportName As String Dim fileName As String Dim criteria As String reportName = "rptYourReportName" fileName = "C:\tmp\report_export_file.pdf" TempVars.Add "SomeTextFieldCriteriaForPdfExport", "ABC" TempVars.Add "SomeNumberFieldCriteriaForPdfExport", 10 DoCmd.OutputTo acOutputReport, reportName, acFormatPDF, fileName TempVars.Remove "SomeTextFieldCriteriaForPdfExport" TempVars.Remove "SomeNumberFieldCriteriaForPdfExport" End Sub

Der Code sieht so auch nicht zu furchtbar aus. Dennoch besteht jetzt diese indirekte Abhängigkeit von den TempVars, die ich lieber vermeiden würde.

Fazit

Für die meisten Anwendungsfälle empfehle ich weiterhin den einfacheren Ansatz, zunächst den Bericht ausgeblendeten mit den erforderlichen Kriterien zu öffnen und dann den PDF-Export zu starten. Dabei besteht nur eine einseitige Abhängigkeit von der VBA-Prozedur zum Bericht. – Ein klares Design.

Wenn du dich jedoch in einer Situation befindest, in der die Performance durch das zweimalige Öffnen und Rendern des Berichts deutlich beeinträchtigt wird, solltest du den alternativen Ansatz mit TempVars verwenden. Es führt zu Abhängigkeiten zwischen dem Bericht, dem Code und der TempVars-Sammlung. Dies ist ein unsauberes und verworrenes Design. Dennoch können die enormen Performancesteigerungen, die mit diesem Ansatz erzielt werden können, dieses suboptimale Design rechtfertigen.

Share this article: Share on Facebook Tweet Share on LinkedIn Share on XING

Abonniere meinen Newsletter

*

Ich werde Deine Email-Addresse niemals weitergeben. Du kannst den Newsletter jederzeit abbestellen.
Die Emailliste wird bei Mailchimp in den USA gespeichert. Diese Auftragsverarbeitung ist vertraglich geregelt. Weitere Details in der Datenschutzerklärung.

Vorteile des Newsletter-Abos



© 1999 - 2024 by Philipp Stiefel - Datenschutzerklärung