Mit Bild
Parameter-Abfragen dienen dazu, in Access-Datenbanken wechselnde Filter zu ermöglichen. Das ist technisch in Ordnung, aber oft nicht besonders komfortabel für die Benutzer. Daher können Sie auf die Inhalte von Formularen verweisen, anstatt jedes Mal erneut die Werte im automatisch erzeugten Standarddialog eingeben zu müssen. Lorenz Hölscher zeigt, wie Sie das mit ein paar Zeilen VBA-Code sehr elegant lösen.
Mit Bild
Anhand einer einfachen Datenbank möchte ich Ihnen zeigen, wie Sie aus einer langweiligen Parameter-Abfrage mit Nerv-Potential einen sehr benutzerfreundlichen Zugriff auf Daten machen können.
Mit Bild
Was sind Parameter-Abfragen?
Wenn Sie sich mit Parameter-Abfragen noch nicht auskennen, hilft Ihnen der Beitrag "Komfortables Abfragen: Parameterabfragen" weiter, der die Technik ausführlich erläutert.
Mit Bild
Als Ausgangsdaten dienen zwei Tabellen aus der Nordwind-Datenbank (eine Beispiel-Datenbank von Microsoft aus früheren Access-Versionen) mit Bestellungen und den zugehörigen Kunden, die über eine Kundenkennung verbunden sind. Die Tabelle tblKunden sieht so aus:
Mit Bild
Tabelle tblKunden
Mit Bild
Dazu kommt eine Tabelle tblBestellungen mit den Bestellungen, wobei hier nur deren Stammdaten enthalten sind, da die Bestelldetails in einer weiteren 1:n-verknüpften Tabelle gespeichert werden müssen. Für die Daten der Bestellungen-Tabelle ist nur wichtig, dass die Kundenkennungen zu tblKunden passen, wie der Ausschnitt hier zeigt:
Mit Bild
Tabelle Bestellungen
Mit Bild
Mit einer "normalen" Parameter-Abfrage könnten Sie nun beispielsweise alle Bestellungen für einen bestimmten Kunden herausfinden. Dazu geben Sie die gewünschten Felder (oder wie hier das "*" für alle Felder) im Abfrage-Entwurf an und das Feld bstKndKennungRef mit dem Kriterium [Welcher Kunde?]:
Mit Bild
Parameterabfrage für wechselnde Kunden
Mit Bild
Wahlweise können Sie das auch als SQL-Statement eingeben:
Mit Bild
SELECT tblBestellungen.* FROM tblBestellungen WHERE (((tblBestellungen.bstKndKennungRef)=[Welcher Kunde?]));
Mit Bild
oder kürzer ohne die mehrfache explizite Nennung des Tabellennamens:
Mit Bild
SELECT * FROM tblBestellungen WHERE bstKndKennungRef=[Welcher Kunde?];
Mit Bild
Wichtig ist dabei, dass im Kriterium die eckigen Klammern vorhanden sind und deren Inhalt den Regeln für Feldnamen folgt (beispielsweise keine Punkte oder Ausrufezeichen). Sobald Sie diese Abfrage starten, wird sie automatisch den folgenden Dialog anzeigen und die (hier schon erfolgte) Eingabe einer Kundenkennung erwarten:
Mit Bild
Eingabedialog zur Parameterabfrage
Mit Bild
Der Feldname (also der Text innerhalb der eckigen Klammern) erscheint hier im Dialog, daher wähle ich die Frageform und einen lesbaren Text mit Leerzeichen. Nach Bestätigung des Dialogs erscheint das Ergebnis der Abfrage mit diesem Filter:
Mit Bild
Ergebnis der Parameterabfrage für 'ALFKI'
Mit Bild
So weit ist das die übliche technische Prozedur für Parameter-Abfragen in Access. Das ließe sich noch bedeutend benutzerfreundlicher gestalten, wenn auch Jokerzeichen wie "*" und "?" erlaubt wären. Ergänzen Sie dazu den Entwurf um das Schlüsselwort Wie:
Mit Bild
Verbesserter Entwurf der Parameterabfrage
Mit Bild
Sie können das auch in der SQL-Ansicht machen, indem Sie das Gleichheitszeichen durch das Schlüsselwort LIKE ersetzen:
Mit Bild
SELECT * FROM tblBestellungen WHERE bstKndKennungRef LIKE [Welcher Kunde?];
Mit Bild
Damit ist auch die Eingabe von "A*" oder sogar nur "*" als Kundenkennung möglich:
Mit Bild
Jetzt sind auch Jokerzeichen als Parameter möglich.
Mit Bild
Trotz allem bleibt es jedoch lästig, dass keine vorhandenen Kundenkennungen in einer Ausklappliste angeboten werden. Das möchte ich nun verbessern.
Mit Bild
Formular statt Parameter-Dialog
Mit Erstellen/Formulare/Formular-Entwurf bereiten Sie dazu ein eher kleines Formular vor, welches keine Datensatzquelle benötigt. Speichern Sie es als frmKundenAuswahl:
Mit Bild
Ein kleines und noch leeres Formular im Entwurf
Mit Bild
Erstellen Sie außerdem eine Abfrage qryKundenSortiert mit dem folgenden SQL-Statement:
Mit Bild
SELECT kndKennung, [kndName] & " (" & [kndOrt] & ")" AS wer FROM tblKunden ORDER BY kndKennung;
Mit Bild
Damit können Sie anschließend im Formular die auszuwählenden Kunden sortiert und übersichtlich anzeigen:
Mit Bild
Die Kunden sind so sortiert.
Mit Bild
Auf dem Formular-Entwurf fügen Sie nun ein Kombinationsfeld ein, beschriften es mit "Kunde:" und benennen es als cmbKunden. Als Datensatzherkunft erhält es die soeben vorbereitete Abfrage qryKundenSortiert:
Mit Bild
Das Kombinationsfeld cmbKunden mit seinen Eigenschaften
Mit Bild
Standardwert für Kombinationsfeld
Damit das Kombinationsfeld auch direkt nach dem Öffnen des Formulars einen Wert ausgewählt hat, gibt es zwei Möglichkeiten: Entweder nennen Sie in der Eigenschaft Standardwert einen konkreten Inhalt (hier beispielsweise "ALFKI") oder Sie lassen per VBA den jeweils ersten Wert auswählen.
Die VBA-Variante ist sicherer, weil sie auch dann funktioniert, wenn ALFKI mal nicht mehr als Inhalt enthalten sein sollte. Dazu geben Sie im Formular-Modul diesen Code ein:
Private Sub Form_Current() Me.cmbKunden.Value = Me.cmbKunden.Column(0, 0) End Sub
Das Kombinationsfeld wählt dadurch beim Anzeigen des Formulars den Eintrag der ersten Spalte in der ersten Zeile aus, die jeweils ab 0 gezählt werden.
Mit Bild
Für die Formular-Eigenschaften selber könnten Sie noch diese Werte einstellen, damit es besser aussieht:
Datensatzmarkierer: Nein
Navigationsschaltflächen: Nein
Bildlaufleisten: Nein
MinMaxSchaltflächen: Min vorhanden
PopUp: Ja
Diese Einstellungen sind sinnvoll, weil dieses Formular selber ja keine Datensätze anzeigt oder bearbeitet, sondern lediglich Platz für ein Kombinationsfeld (mit darin enthaltenen Daten) bietet. Das fertige Formular sieht nun so aus:
Mit Bild
Das fertige Formular mit Kombinationsfeld
Mit Bild
Die PopUp-Eigenschaft des Formulars steht auf Ja, damit es immer im Vordergrund bleibt, selbst wenn es demnächst nicht den Fokus hat.
Mit Bild
Schöneres Kombinationsfeld
Die erste Spalte ist versteckt.
Sie können die ausklappende Liste etwas schöner und lesefreundlicher gestalten, indem Sie die zweite Spalte mit den echten Namen anzeigen statt der Kürzel. Dazu wechseln Sie in die Entwurfsansicht des Formulars, markieren das Kombinationsfeld und ändern dessen Eigenschaften:
Spaltenanzahl: 2
Spaltenbreiten: 0cm;7cm
Listenbreite: 7cm
Mit Bild
Parameter aus Formular ermitteln
Jetzt geht es darum, dass die Parameter-Abfrage nicht mehr den Dialog anzeigt, sondern stattdessen die Auswahl im Formular benutzt. Dazu öffnen Sie die Entwurfs-Ansicht der Abfrage und klicken dort in das Kriterium mit den eckigen Klammern.
Mit dem Befehl Abfragetools Entwurf/Abfragesetup/Generator (das Symbol zeigt einen kleinen Zauberstab an) oder dem Tastenkürzel Strg+F2 können Sie anschließend im Ausdrucks-Generator direkt das Kombinationsfeld cmbKunden auswählen und per Doppelklick in das Textfeld oben übernehmen lassen:
Mit Bild
Da frmKundenAuswahl geladen ist, finden Sie es schnell im Ausdrucks-Generator
Mit Bild
Die nach dem Doppelklick noch übrigbleibenden Reste des vorherigen Codes löschen Sie manuell und bestätigen den Ausdrucks-Generator mit OK. Damit steht statt der eckigen Klammern mit der Frage nun ein Verweis auf das Formular im Abfrage-Entwurf:
Mit Bild
Die geänderte Parameterabfrage
Mit Bild
Nun lässt sich in der Combobox sehr bequem ein Eintrag auswählen, dessen Daten dann beim nächsten Aufruf der Abfrage als Filter benutzt werden:
Mit Bild
Die Abfrage kann mit 'Alle aktualisieren' aktualisiert werden.
Mit Bild
Nach einer geänderten Kunden-Auswahl im Formular frmKundenAuswahl müssen Sie entweder die Abfrage neu öffnen oder deren Daten mit dem Befehl "Alle aktualisieren" aktualisieren.
Mit Bild
Abfrage-Start ohne Formular?
Das funktioniert alles so lange einwandfrei, wie das Formular frmKundenAuswahl offen ist. Wenn Sie die Abfrage aber starten, ohne dass es geöffnet ist, erhalten Sie diese Fehlermeldung:
Mit Bild
Fehlermeldung ohne geöffnetes PopUp-Formular
Mit Bild
Access kann auf die Inhalte eines geschlossenen Formulars nicht zugreifen. Daher sollten Sie diesen Datenzugriff mit VBA kapseln, damit Sie das notfalls abfangen können. Anstatt also im SQL-Statement direkt auf ein Formular-Feld zu verweisen, geschieht dies innerhalb einer Funktion.
Dazu brauchen Sie erst einmal eine VBA-Funktion, die hier HoleKundenKennung heißt und auf das Formular zugreift:
Mit Bild
Function HoleKundenKennung() As String HoleKundenKennung = Forms("frmKundenAuswahl").cmbKunden.Value End Function
Mit Bild
Diese Funktion können Sie in einem beliebigen Modul dieser Datenbank erstellen:
Mit Bild
Eigene VBA-Funktion
Mit Bild
Das SQL-Statement in der Abfrage verändert sich entsprechend, damit das Funktionsergebnis als Filter benutzt wird. Sie können auch hier mit Strg+F2 den Ausdrucks-Generator aufrufen oder den Namen der Funktion mit folgendem Klammerpaar direkt schreiben:
Mit Bild
Abfrage-Entwurf mit eigener VBA-Funktion und Ausdrucks-Generator
Mit Bild
Natürlich verändert sich mit diesem kurzen VBA-Code im Moment bestenfalls die erscheinende Fehlermeldung, wenn das Formular mal nicht geöffnet ist. Aber Sie haben nun alle Möglichkeiten der Fehlerbehandlung innerhalb von VBA:
Mit Bild
Function HoleKundenKennung() As String On Error Resume Next HoleKundenKennung = Forms("frmKundenAuswahl").cmbKunden.Value If Err.Number <> 0 Then 'HoleKundenKennung = "ALFKI" MsgBox "Fehler Nr. " & Err.Number & ":" & vbCrLf & Err.Description, vbCritical End If End Function
Mit Bild
Wie im obigen VBA-Code als Kommentar (mit Hochkomma davor) schon zu sehen ist, können Sie alternativ auch einfach einen festen Wert zurückgeben oder mit "*" alle Datensätze anzeigen. Dann weiß der Benutzer allerdings noch nicht, dass ein Fehler aufgetreten ist.
Mit Bild
Fehler in VBA behandeln
Der Umgang mit Laufzeitfehlern in Access-VBA ist nicht Thema dieses Beitrags, weil das bereits in "Syntax-Fehler, logische Fehler, Laufzeitfehler, Datentyp-Probleme" behandelt wird.
Mit Bild
Wenn das Formular nicht geöffnet war, tritt direkt ein Fehler auf. In dem Fall erscheint eine Fehlermeldung mit erläuterndem Text:
Mit Bild
Neue Fehlermeldung ohne geöffnetes PopUp-Formular
Mit Bild
Sie können natürlich auch beides kombinieren, die vorherige Chance auf Eingabe der Kundenkennung und die jetzige bessere Fehlermeldung:
Mit Bild
Function HoleKundenKennung() As String On Error Resume Next HoleKundenKennung = Forms("frmKundenAuswahl").cmbKunden.Value If Err.Number <> 0 Then HoleKundenKennung = InputBox("Kundenkennung?" & vbCrLf & Err.Description, , "ALFKI") If HoleKundenKennung = "" Then End End If End If End Function
Mit Bild
Die InputBox()-Funktion erlaubt die einfache Eingabe eines Textes, der hier direkt mit dem Wert ALFKI vorbesetzt wurde. Da diese Funktion beim Abbruch zudem einen Leerstring zurückgibt, lässt sich damit direkt der ganze Aufruf der Abfrage abbrechen. Die Meldung sieht nun so aus:
Mit Bild
Verbesserte Fehlermeldung mit Eingabemöglichkeit
Mit Bild
Leider ist es nicht möglich, in dieser Funktion das offensichtlich nur fehlende Formular noch schnell zu öffnen. Access lässt das beim gleichzeitig stattfindenden Öffnen einer Abfrage nicht zu.
Mit Bild
Fazit
Mit wenigen Zeilen VBA-Code können Sie aus der eher spröden Technik der Parameter-Abfragen eine benutzerfreundliche Bedienung zaubern. Dabei lassen sich auch eventuell auftretende Fehler elegant umgehen und verständlich beheben.