Elegantere Parameter-Abfragen in Access

Parameter-Abfragen mit VBA benutzerfreundlicher gestalten

Parameter-Abfragen dienen
dazu, in Access-Datenbanken wechselnde Filter zu ermöglichen.

∅ 4.6 / 20 Bewertungen

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.

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.

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.

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:

tabellekunden01-jpg

Tabelle tblKunden

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:

tabellebestellungen01-jpg

Tabelle Bestellungen

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?]:

paramabfrage01-jpg

Parameterabfrage für wechselnde Kunden

Wahlweise können Sie das auch als SQL-Statement eingeben:

SELECT tblBestellungen.*
FROM tblBestellungen
WHERE (((tblBestellungen.bstKndKennungRef)=[Welcher Kunde?]));

oder kürzer ohne die mehrfache explizite Nennung des Tabellennamens:

SELECT *
FROM tblBestellungen
WHERE bstKndKennungRef=[Welcher Kunde?];

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:

paramabfrage02-jpg

Eingabedialog zur Parameterabfrage

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:

paramabfrage03-jpg

Ergebnis der Parameterabfrage für 'ALFKI'

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:

paramabfrage04-jpg

Verbesserter Entwurf der Parameterabfrage

Sie können das auch in der SQL-Ansicht machen, indem Sie das Gleichheitszeichen durch das Schlüsselwort LIKE ersetzen:

SELECT *
FROM tblBestellungen
WHERE bstKndKennungRef LIKE [Welcher Kunde?];

Damit ist auch die Eingabe von "A*" oder sogar nur "*" als Kundenkennung möglich:

paramabfrage05-jpg

Jetzt sind auch Jokerzeichen als Parameter möglich.

Trotz allem bleibt es jedoch lästig, dass keine vorhandenen Kundenkennungen in einer Ausklappliste angeboten werden. Das möchte ich nun verbessern.

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:

frmkundenauswahl01-jpg

Ein kleines und noch leeres Formular im Entwurf

Erstellen Sie außerdem eine Abfrage qryKundenSortiert mit dem folgenden SQL-Statement:

SELECT kndKennung, [kndName] & " (" & [kndOrt] & ")" AS wer
FROM tblKunden
ORDER BY kndKennung;

Damit können Sie anschließend im Formular die auszuwählenden Kunden sortiert und übersichtlich anzeigen:

qrykundensortiert01-jpg

Die Kunden sind so sortiert.

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:

frmkundenauswahl02-jpg

Das Kombinationsfeld cmbKunden mit seinen Eigenschaften

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.

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:

frmkundenauswahl03-jpg

Das fertige Formular mit Kombinationsfeld

Die PopUp-Eigenschaft des Formulars steht auf Ja, damit es immer im Vordergrund bleibt, selbst wenn es demnächst nicht den Fokus hat.

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

Die interne Auswahl geschieht weiterhin über die erste (nun aber unsichtbare) Spalte, obwohl das Kombinationsfeld jetzt die zweite Spalte anzeigt:
frmkundenauswahl04-jpg

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:

qrykundensortiert02-jpg

Da frmKundenAuswahl geladen ist, finden Sie es schnell im Ausdrucks-Generator

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:

qrykundensortiert03-jpg

Die geänderte Parameterabfrage

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:

paramabfrage06-jpg

Die Abfrage kann mit 'Alle aktualisieren' aktualisiert werden.

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.

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:

fehler01-jpg

Fehlermeldung ohne geöffnetes PopUp-Formular

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:

Function HoleKundenKennung() As String
    HoleKundenKennung = Forms("frmKundenAuswahl").cmbKunden.Value
End Function

Diese Funktion können Sie in einem beliebigen Modul dieser Datenbank erstellen:

vba01-jpg

Eigene VBA-Funktion

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:

paramabfrage07-jpg

Abfrage-Entwurf mit eigener VBA-Funktion und Ausdrucks-Generator

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:

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

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.

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.

Wenn das Formular nicht geöffnet war, tritt direkt ein Fehler auf. In dem Fall erscheint eine Fehlermeldung mit erläuterndem Text:

fehler02-jpg

Neue Fehlermeldung ohne geöffnetes PopUp-Formular

Sie können natürlich auch beides kombinieren, die vorherige Chance auf Eingabe der Kundenkennung und die jetzige bessere Fehlermeldung:

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

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:

fehler03-jpg

Verbesserte Fehlermeldung mit Eingabemöglichkeit

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.

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.